PK ؐj?oa,mimetypeapplication/epub+zipPKؐj?iTunesMetadata.plist} artistName Oracle Corporation book-info cover-image-hash 372883033 cover-image-path OEBPS/dcommon/oracle-small.JPG package-file-hash 357244611 publisher-unique-id E10186-02 unique-id 379857691 genre Oracle Documentation itemName Oracle® Fusion Middleware Application Developer's Guide for Oracle Identity Management, 11g Release 1 (11.1.1) releaseDate 2010-12-13T19:0:36Z year 2011 PK9}PKؐj?META-INF/container.xml PKYuPKؐj?OEBPS/plsql_ext.htmt Using the API Extensions in PL/SQL

6 Using the API Extensions in PL/SQL

This chapter explains how to use PL/SQL extensions to the standard directory APIs to manage and authenticate users. Note that the Oracle extensions do not include PL/SQL APIs that create users. The Oracle extensions to the standard APIs are documented in full in Chapter 11.

This chapter contains these topics:

6.1 Sample Code

Sample code is available at this URL:

http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications–Oracle Application Server.

6.2 Installing the PL/SQL Extensions

The PL/SQL extensions are installed with the DBMS_LDAP package when the Oracle database is installed. You must run the script $ORACLE_HOME/rdbms/admin/catldap.sql.

6.3 Using Handles to Access Directory Data

Most of the extensions described in this chapter are helper functions. They access data about specific LDAP entities such as users, groups, realms, and applications. In many cases, these functions must pass a reference to one of these entities to the standard API functions. To do this, the API extensions use opaque data structures called handles. The steps that follow show an extension creating a user handle:

  1. Establish an LDAP connection or get one from a pool of connections.

  2. Create a user handle from user input. This could be a DN, a GUID, or a single sign-on user ID.

  3. Authenticate the user with the LDAP connection handle, user handle, or credentials.

  4. Free the user handle.

  5. Close the LDAP connection, or return the connection back to the connection pool.

6.4 Managing Users

The steps that follow show how the DBMS_LDAP_UTL package is used to create and use a handle that retrieves user properties from the directory.

  1. Invoke DBMS_LDAP_UTL.create_user_handle(user_hd, user_type, user_id) to create a user handle from user input. The input can be a DN, a GUID, or a single sign-on user ID.

  2. Invoke DBMS_LDAP_UTL.set_user_handle_properties(user_hd, property_type, property) to associate a realm with the user handle.

  3. Invoke DBMS_LDAP_UTL.get_user_properties(ld, user_handle, attrs, ptype, ret_pset_coll) to place the attributes of a user entry into a result handle.

  4. Invoke DBMS_LDAP_UTL.get_property_names(pset, property_names) and DBMS_LDAP_UTL.get_property_values(pset, property_name, property_values) to extract user attributes from the result handle that you obtained in step 3.

6.5 Authenticating Users

Use DBMS_LDAP_UTL.authenticate_user(session, user_handle, auth_type, cred, binary_cred) to authenticate a user to the directory. This function compares the password provided by the user with the password attribute in the user's directory entry.

6.6 Dependencies and Limitations of the PL/SQL LDAP API

The PL/SQL LDAP API for this release has the following limitations:

  • The LDAP session handles obtained from the API are valid only for the duration of the database session. The LDAP session handles cannot be written to a table and reused in other database sessions.

  • Only synchronous versions of LDAP API functions are supported in this release.

    The PL/SQL LDAP API requires a database connection to work. It cannot be used in client-side PL/SQL engines (like Oracle Forms) without a valid database connection.

PK3PKؐj?OEBPS/index.htm Index

Index

A  C  D  E  F  H  I  J  L  N  O  P  R  S  T  W 

A

abandoning an operation, 8.2.10
access control, 2.3.4, 2.3.4.2, 2.3.4.2
and authorization, 2.3.4.2
access control information (ACI), 2.3.4.2
attributes, 2.3.4.2
directives
format, 2.3.4.2
Access Control List (ACL), 2.3.4.2
access control lists (ACLs), 2.3.4.2
ACI. See access control information (ACI)
ACLs. See Access Control List (ACL)
anonymous authentication, 2.3.4.1.1, 2.3.4.1.1
application context
provisioning plug-ins, A.5
applications, building
with the C API, 8.4
attributes
types, 2.3.2
values, 2.3.2
authentication, 2.3.4, 2.3.4.1, 2.3.4.1
anonymous, 2.3.4.1.1, 2.3.4.1.2
certificate-based, 2.3.4.1.3
modes, SSL, 8.1.1, 8.1.1
one-way SSL, 2.3.4.1.3
options, 2.3.4.1
password-based, 2.3.4.1.2
SSL, 2.3.4.1.3, 2.3.4.1.3, 8.1.1
none, 8.1.1
one-way, 8.1.1
two-way, 8.1.1
strong, 2.3.4.1.3
to a directory server
enabling, 2.6
enabling, by using DBMS_LDAP, 2.6.2
enabling, by using the C API, 2.6.1
to the directory, 8.2.5
two-way SSL, 2.3.4.1.3
authorization, 2.3.4, 2.3.4.2
authorization ID, 2.3.4.1

C

C API
functions
abandon, 8.2.10.1
abandon_ext, 8.2.10.1
add, 8.2.9.7, 8.2.9.7
add_ext_s, 8.2.9.7
add_s, 8.2.9.7
compare, 8.2.9.4
compare_ext, 8.2.9.4
compare_ext_s, 8.2.9.4
compare_s, 8.2.9.4
count_entries, 8.2.14.1
count_references, 8.2.14.1
count_values, 8.2.14.3
count_values_len, 8.2.14.3
delete, 8.2.9.8
delete_ext, 8.2.9.8
delete_ext_s, 8.2.9.8
delete_s, 8.2.9.8
dn2ufn, 8.2.14.4
err2string, 8.2.12.1
explode_dn, 8.2.14.4
explode_rdn, 8.2.14.4
extended_operation, 8.2.9.9
extended_operation_s, 8.2.9.9
first_attribute, 8.2.14.2
first_entry, 8.2.14.1
first_message, 8.2.13.1
first_reference, 8.2.14.1
get_dn, 8.2.14.4
get_entry_controls, 8.2.14.5
get_option, 8.2.3.1
get_values, 8.2.14.3
get_values_len, 8.2.14.3
init_ssl call, 8.1.1.1
modify, 8.2.9.5
modify_ext, 8.2.9.5
modify_ext_s, 8.2.9.5
modify_s, 8.2.9.5
msgid, 8.2.11.1
msgtype, 8.2.11.1
next_attribute, 8.2.14.2
next_entry, 8.2.14.1
next_message, 8.2.13.1
next_reference, 8.2.14.1
parse_extended_result, 8.2.12.1
parse_reference, 8.2.14.6
parse_result, 8.2.12.1
parse_sasl_bind_result, 8.2.12.1
rename, 8.2.9.6
rename_s, 8.2.9.6
result, 8.2.11.1
sasl_bind, 8.2.5.1
sasl_bind_s, 8.2.5.1
search_st, 8.2.9.1
set_option, 8.2.3.1
simple_bind, 8.2.5.1
simple_bind_s, 8.2.5.1
unbind_ext, 8.2.8.1
unbind_s, 8.2.8.1
value_free, 8.2.14.3
value_free_len, 8.2.14.3
sample usage, 8.3
summary, 8.2.1
usage with SSL, 8.3.1, 8.3.1
usage without SSL, 8.3.2, 8.3.2
certificate authority, 2.3.4.1.3
certificate-based authentication, 2.3.4.1.3
certificates, 2.3.4.1.3
children of an entry, listing, 8.2.9.3
components
Oracle Identity and Access Management SDK, 1.3.2
CONNECT_BY control, 3.5.1
controls, working with, 3.4.2, 3.4.5, 8.2.7

D

DAP Information Model, 2.3.2
data
integrity, 2.3.4, 2.3.4.3, 2.3.4.3
privacy, 2.3.4, 2.3.4.4, 2.3.4.4
data-type summary, 9.3
DBMS_LDAP package
searching by using, 2.7
DBMS_LDAP_UTL
data-types, 11.4
function return codes, 11.3
group-related subprograms
about, 11.1
function create_group_handle, 11.2.2.1
function get_group_dn, 11.2.2.4
function get_group_properties, 11.2.2.3
function set_group_handle_properties, 11.2.2.2
miscellaneous subprograms
about, 11.1
function check_interface_version, 11.2.5.10
function create_mod_propertyset, 11.2.5.6
function get_property_names, 11.2.5.2
function get_property_values, 11.2.5.3
function get_property_values_len, 11.2.5.4
function normalize_dn_with_case, 11.2.5.1
function populate_mod_propertyset, 11.2.5.7
procedure free_handle, 11.2.5.9
procedure free_mod_propertyset, 11.2.5.8
procedure free_propertyset_collection, 11.2.5.5
subscriber-related subprograms
about, 11.1
function create_subscriber_handle, 11.2.3.1
function get_subscriber_dn, 11.2.3.3
function get_subscriber_properties, 11.2.3.2
user-related subprograms
about, 11.1
function authenticate_user, 11.2.1.1
function check_group_membership, 11.2.1.8
function create_user_handle, 11.2.1.2
function get_group_membership, 11.2.1.10
function get_user_dn, 11.2.1.7
function get_user_extended_properties, 11.2.1.6
function get_user_properties, 11.2.1.4
function locate_subscriber_for_user, 11.2.1.9
function set_user_handle_properties, 11.2.1.3, 11.2.1.3
function set_user_properties, 11.2.1.5
DBMS_LDAP_UTL PL/SQL Reference, 11
dependencies and limitations, 8.5
C API, 8.5
DES40 encryption, 2.3.4.4
directives, 2.3.4.2
Directory Information Tree, 2.3.1
directory information tree (DIT), 2.3.1
directory operations
provisioning plug-ins, A.5
directory server discovery, 4.7
distinguished names, 2.3.1
components of, 2.3.1
format, 2.3.1
DNs. see distinguished names.
documentation, related, Preface
dynamic password verifiers
controls, 3.4.2, 3.4.5
creating, 3.4.1
parameters, 3.4.2, 3.4.2

E

encryption
DES40, 2.3.4.4
levels available in Oracle Internet Directory, 2.3.4.4
RC4_40, 2.3.4.4
entries
distinguished names of, 2.3.1
locating by using distinguished names
naming, 2.3.1
reading, 8.2.9.2
errors
handling and parsing results, 8.2.11.1
exception summary, 9.2

F

filters, 2.7.3
formats, of distinguished names, 2.3.1

H

header files and libraries, required, 8.4
hierarchical search, 3.5
history of LDAP, 2.2

I

integrity, data, 2.3.4.3
interface calls, SSL, 8.1.1.1

J

Java, 1.3.1, 2.4.4
Java API reference
class descriptions
Property class, 5.4
PropertySet class, 5.4
PropertySetCollection class, 5.4
Java APIs for Oracle Internet Directory, 10
JAZN
see Oracle Application Server Java Authentication and Authorization Service
JNDI, 1.3.1, 2.4.4
JNDI location, 10

L

LDAP
functional model, 2.3.3
history, 2.2
information model, 2.3.2
messages, obtaining results and peeking inside, 8.2.11
naming model, 2.3.1
operations, performing, 8.2.9
security model, 2.3.4
session handle options, 8.2.3
in the C API, 2.6
sessions
initializing, 2.5
version 2 C API, 8.1
LDAP APIs, 1.3.3.3
LDAP Functional Model, 2.3.3
LDAP Models, 2.3
LDAP Naming Model, 2.3.1
LDAP Security Model, 2.3.4
ldap-bind operation, 2.3.4.1
login name
finding, 5.10

N

naming entries, 2.3.1

O

one-way SSL authentication, 2.3.4.1.3, 8.1.1
OpenLDAP Community, Preface
operational attributes
ACI, 2.3.4.2
Oracle Application Server Java Authentication and Authorization Service
defined, 1.1
Oracle extensions
application
deinstallation logic, 1.3.3.2
runtime logic, 1.3.3.2
shutdown logic, 1.3.3.2
startup and bootstrap logic, 1.3.3.2
group management functionality, 4.5
programming abstractions
for Java language, 5, 6
for PL/SQL language, 6.3
programming abstractions for Java language, 5, 6
user management functionality, 5, 6
Oracle extensions to support SSL, 8.1
Oracle Identity and Access Management
modifying existing applications, 1.2
Oracle Identity Management
integrating applications with
supported services, 1.1
Oracle SSL call interface, 8.1
Oracle SSL extensions, 8.1.1
Oracle SSL-related libraries, 8.5
Oracle system libraries, 8.5
Oracle wallet, 8.1.1.2
Oracle Wallet Manager, 8.1.1.2
required for creating wallets, 8.5
Oracle xxtensions
what an LDAP-integrated application looks like, 1.3.3.1
overview of LDAP models, 2.3

P

password-based authentication, 2.3.4.1.2
passwords
policies, 2.3.4.5
permissions, 2.3.4, 2.3.4.2
PL/SQL API, 9
contains subset of C API, 2.4.3
data-type summary, 9.3
exception summary, 9.2
functions
add_s, 9.4.27, 9.4.27
ber_free, 9.4.35
bind_s, 9.4.3, 9.4.3
compare_s, 9.4.5, 9.4.5
count_entries, 9.4.10, 9.4.10
count_values, 9.4.29, 9.4.29
count_values_len, 9.4.30, 9.4.30
create_mod_array, 9.4.19, 9.4.19
dbms_ldap.init, 9.4.1
delete_s, 9.4.16, 9.4.16
err2string, 9.4.18, 9.4.18
explode_dn, 9.4.32, 9.4.32
first_attribute, 9.4.11, 9.4.11
first_entry, 9.4.8, 9.4.8
get_dn, 9.4.13, 9.4.13
get_values, 9.4.14, 9.4.14
get_values_len, 9.4.15, 9.4.15
init, 9.4.1, 9.4.1
modify_s, 9.4.26, 9.4.26
modrdn2_s, 9.4.17, 9.4.17
msgfree, 9.4.34
next_attribute, 9.4.12, 9.4.12
next_entry, 9.4.9, 9.4.9
open_ssl, 9.4.33, 9.4.33, 9.4.34, 9.4.35, 9.4.35
rename_s, 9.4.31, 9.4.31
search_s, 9.4.6, 9.4.6
search_st, 9.4.7, 9.4.7
simple_bind_s, 9.4.2, 9.4.2
unbind_s, 9.4.4, 9.4.4
loading into database, 2.4.3
procedures
free_mod_array, 9.4.28
populate_mod_array (binary version), 9.4.21
populate_mod_array (string version), 9.4.20
subprograms, 9.4, 9.4
summary, 9.1, 9.1
plug-ins
provisioning interface, A
privacy, data, 2.3.4, 2.3.4.4, 2.3.4.4
privileges, 2.3.4, 2.3.4.2
procedures, PL/SQL
free_mod_array, 9.4.28
populate_mod_array (binary version), 9.4.21
populate_mod_array (string version), 9.4.20
provisioning interface plug-ins, A
provisioning plug-ins
directory operations, A.5
getting application context, A.5

R

RC4_40 encryption, 2.3.4.4
RDNs. see relative distinguished names (RDNs)
related documentation, Preface
relative distinguished names (RDNs), 2.3.1
results, stepping through a list of, 8.2.13
RFC 1823, 8.5

S

sample C API usage, 8.3, 8.3
SDK components, 1.3.2
search
hierarchical, 3.5
results
parsing, 8.2.14
scope, 2.7.2
search-related operations, flow of, 2.7.1
security, within Oracle Internet Directory environment, 2.3.4
service location record, 4.7
sessions
closing, 8.2.8
enabling termination by using DBMS_LDAP, 2.8.2
initializing
by using DBMS_LDAP, 2.5.2
by using the C API, 2.5.1
session-specific user identity, 2.3.4.1
simple authentication, 2.3.4.1.2, 2.3.4.1.2
Smith, Mark, Preface, Preface
SSL
authentication modes, 8.1.1
default port, 2.3.4.1.3
handshake, 8.1.1.1
interface calls, 8.1.1.1, 8.1.1.1
no authentication, 2.3.4.1.3
one-way authentication, 2.3.4.1.3
Oracle extensions, 8.1, 8.1.1
provide encryption and decryption, 8.1.1
two-way authentication, 2.3.4.1.3
wallets, 8.1.1.2
SSO login name
finding, 5.10
strong authentication, 2.3.4.1.3

T

TCP/IP socket library, 8.5
two-way authentication, SSL, 8.1.1
types of attributes, 2.3.2

W

wallets
SSL, 8.1.1.2
support, 8.1.1.2
PK;[`PKؐj? OEBPS/toc.htm Table of Contents

Contents

List of Figures

List of Tables

Title and Copyright Information

Preface

What's New in the SDK?

Part I Programming for Oracle Identity Management

1 Developing Applications for Oracle Identity Management

2 Developing Applications with Standard LDAP APIs

3 Extensions to the LDAP Protocol

4 Developing Applications With Oracle Extensions to the Standard APIs

5 Using the Java API Extensions to JNDI

6 Using the API Extensions in PL/SQL

7 Developing Provisioning-Integrated Applications

Part II Oracle Internet Directory Programming Reference

8 C API Reference

9 DBMS_LDAP PL/SQL Reference

10 Java API Reference

11 DBMS_LDAP_UTL PL/SQL Reference

12 Oracle Directory Integration and Provisioning Java API Reference

13 Oracle Directory Integration Platform PL/SQL API Reference

Part III Appendixes

A Java Plug-ins for User Provisioning

B DSML Syntax

C Migrating from Netscape LDAP SDK API to Oracle LDAP SDK API

Index

PK݌ PKؐj?OEBPS/img_text/oiddg007.htmB Description of the illustration oiddg007.eps

This illustration shows four hypothetical users connecting to a middle tier. Each user has a connection, for a total of four connections. The middle tier then connects to Oracle Internet Directory by using only two connections. The directory contains data for groups, subscribers, and applications.

PKVPKؐj?OEBPS/img_text/oiddg009.htmA Description of the illustration oiddg009.eps

This illustration is described in the text.

PKMPKؐj?OEBPS/sdk_port.htm Migrating from Netscape LDAP SDK API to Oracle LDAP SDK API

C Migrating from Netscape LDAP SDK API to Oracle LDAP SDK API

The Oracle Internet Directory SDK C API is described in Chapter 8, "C API Reference". This Appendix outlines differences between the Netscape LDAP SDK and the Oracle Internet Directory LDAP SDK that are important when migrating code.

C.1 Features

The following features of the Oracle Internet Directory LDAP SDK are different from Netscape's SDK.

C.2 Functions

The following functions are available in Netscape LDAP SDK and not in Oracle LDAP SDK:

  • The Oracle LDAP SDK does not have the function ldap_ber_free(). Use ber_free() instead.

  • The Oracle LDAP SDK does not have the function ldap_get_lderrno() for retrieving the ld error and matched string. You can retrieve this information directly by accessing the field LDAP.ld_matched and LDAP.ld_error. These are the only fields of the LDAP structure that you should ever need to access.

C.3 Macros

  • LDAPS_PORT is not defined in the Oracle LDAP SDK. Use LDAP_SSL_PORT instead.

  • LDAP_AFFECT_MULTIPLE_DSA is not defined in the Oracle LDAP SDK. This is a Netscape-specific macro.

PKɧPKؐj?OEBPS/dbldputl_ref.htm DBMS_LDAP_UTL PL/SQL Reference

11 DBMS_LDAP_UTL PL/SQL Reference

This chapter contains reference material for the DBMS_LDAP_UTL package, which contains Oracle Extension utility functions. The chapter contains these topics:


Note:

Sample code for the DBMS_LDAP_UTL package is available at this URL:
http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications—Fusion Middleware.


11.1 Summary of Subprograms

11.2 Subprograms

This section contains the following topics:

11.2.1 User-Related Subprograms

A user is represented by the DBMS_LDAP_UTL.HANDLE data type. You can create a user handle by using a DN, GUID, or simple name, along with the appropriate subscriber handle. When a simple name is used, additional information from the root Oracle Context and the subscriber Oracle Context is used to identify the user. This example shows a user handle being created:

retval := DBMS_LDAP_UTL.create_user_handle(
user_handle,
DBMS_LDAP_UTL.TYPE_DN,
"cn=user1,cn=users,o=example,dc=com"
);

This user handle must be associated with an appropriate subscriber handle. If, for example, subscriber_handle is o=example,dc=com, the subscriber handle can be associated in the following way:

retval := DBMS_LDAP_UTL.set_user_handle_properties(
user_handle,
DBMS_LDAP_UTL.SUBSCRIBER_HANDLE,
subscriber_handle
);

Common uses of user handles include setting and getting user properties and authenticating the user. Here is a handle that authenticates a user:

retval := DBMS_LDAP_UTL.authenticate_user(
my_session
user_handle
DBMS_LDAP_UTL.AUTH_SIMPLE,
"welcome"
NULL
);

In this example, the user is authenticated using a clear text password welcome.

Here is a handle that retrieves a user's telephone number:

--my_attrs is of type DBMS_LDAP.STRING_COLLECTION
my_attrs(1) :='telephonenumber';  
retval := DBMS_LDAP_UTL.get_user_properties(
my_session,
my_attrs,
DBMS_LDAP_UTL.ENTRY_PROPERTIES,
my_pset_coll
);

11.2.1.1 Function authenticate_user

The function authenticate_user()authenticates the user against Oracle Internet Directory.

Syntax

FUNCTION authenticate_user 
( 
ld IN SESSION, 
user_handle IN HANDLE, 
auth_type IN PLS_INTEGER, 
credentials IN VARCHAR2, 
binary_credentials IN RAW 
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can be called only after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.create_user_handle().

11.2.1.4 Function get_user_properties

The function get_user_properties() retrieves the user properties.

Syntax

FUNCTION get_user_properties 
( 
ld IN SESSION, 
user_handle IN HANDLE, 
attrs IN STRING_COLLECTION, 
ptype IN PLS_INTEGER, 
ret_pset_coll OUT PROPERTY_SET_COLLECTION 
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function requires the following:

  • A valid LDAP session handle, which must be obtained from the DBMS_LDAP.init() function.

  • A valid subscriber handle to be set in the group handle properties if the user type is of DBMS_LDAP_UTL.TYPE_NICKNAME.

This function does not identify a NULL subscriber handle as a default subscriber. The default subscriber can be obtained from DBMS_LDAP_UTL.create_subscriber_handle(), where a NULL subscriber_id is passed as an argument.

If the group type is either DBMS_LDAP_UTL.TYPE_GUID or DBMS_LDAP_UTL.TYPE_DN, the subscriber handle need not be set in the user handle properties. If the subscriber handle is set, it is ignored.

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.create_user_handle().

11.2.1.5 Function set_user_properties

The function set_user_properties() modifies the properties of a user.

Syntax

FUNCTION set_user_properties 
( 
ld IN SESSION, 
user_handle IN HANDLE, 
pset_type IN PLS_INTEGER, 
mod_pset IN PROPERTY_SET, 
mod_op IN PLS_INTEGER 
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can only be called after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.get_user_properties().

11.2.1.6 Function get_user_extended_properties

The function get_user_extended_properties() retrieves user extended properties.

Syntax

FUNCTION get_user_extended_properties 
( 
ld IN SESSION, 
user_handle IN HANDLE, 
attrs IN STRING_COLLECTION 
ptype IN PLS_INTEGER, 
filter IN VARCHAR2, 
rep_pset_coll OUT PROPERTY_SET_COLLECTION 
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can be called only after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.get_user_properties().

11.2.1.9 Function locate_subscriber_for_user

The function locate_subscriber_for_user() retrieves the subscriber for the given user and returns a handle to it.

Syntax

FUNCTION locate_subscriber_for_user 
( 
ld IN SESSION, 
user_handle IN HANDLE, 
subscriber_handle OUT HANDLE 
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can be called only after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.create_user_handle().

11.2.2 Group-Related Subprograms

A group is represented using by using the DBMS_LDAP_UTL.HANDLE data type. A group handle represents a valid group entry. You can create a group handle by using a DN, GUID or a simple name, along with the appropriate subscriber handle. When a simple name is used, additional information from the Root Oracle Context and the Subscriber Oracle Context is used to identify the group. Here is an example of a group handle creation:

retval := DBMS_LDAP_UTL.create_group_handle(
group_handle,
DBMS_LDAP_UTL.TYPE_DN,
"cn=group1,cn=Groups,o=example,dc=com"
);

This group handle has to be associated with an appropriate subscriber handle. For example, given a subscriber handle: subscriber_handle representing o=example,dc=com, the subscriber handle can be associated in the following way:

retval := DBMS_LDAP_UTL.set_group_handle_properties(
group_handle,
DBMS_LDAP_UTL.SUBSCRIBER_HANDLE,
subscriber_handle
);

A sample use of group handle is getting group properties. Here is an example:

my_attrs is of type DBMS_LDAP.STRING_COLLECTION
my_attrs(1) :='uniquemember';
retval := DBMS_LDAP_UTL.get_group_properties(
my_session,
my_attrs,
DBMS_LDAP_UTL.ENTRY_PROPERTIES,
my_pset_coll
);

The group-related subprograms also support membership-related functionality. Given a user handle, you can find out if it is a direct or a nested member of a group by using the DBMS_LDAP_UTL.check_group_membership() function. Here is an example:

retval := DBMS_LDAP_UTL.check_group_membership(
session,
user_handle,
group_handle,
DBMS_LDAP_UTL.DIRECT_MEMBERSHIP

You can also obtain a list of groups that a particular group belongs to, using the DBMS_LDAP_UTL.get_group_membership() function. For example:

my_attrs is of type DBMS_LDAP.STRING_COLLECTION
my_attrs(1) :='cn';
retval := DBMS_LDAP_UTL.get_group_membership(
my_session,
user_handle,
DBMS_LDAP_UTL.DIRECT_MEMBERSHIP,
my_attrs
my_pset_coll
);

11.2.2.3 Function get_group_properties

The function get_group_properties() retrieves the group properties.

Syntax

FUNCTION get_group_properties 
( 
ld IN SESSION, 
group_handle IN HANDLE, 
attrs IN STRING_COLLECTION, 
ptype IN PLS_INTEGER, 
ret_pset_coll OUT PROPERTY_SET_COLLECTION
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function requires the following:

  • A valid LDAP session handle which must be obtained from the DBMS_LDAP.init() function.

  • A valid subscriber handle to be set in the group handle properties if the group type is of: DBMS_LDAP_UTL.TYPE_NICKNAME.

This function does not identify a NULL subscriber handle as a default subscriber. The default subscriber can be obtained from DBMS_LDAP_UTL.create_subscriber_handle(), where a NULL subscriber_id is passed as an argument.

If the group type is either DBMS_LDAP_UTL.TYPE_GUID or DBMS_LDAP_UTL.TYPE_DN, the subscriber handle does not have to be set in the group handle properties. If the subscriber handle is set, it is ignored.

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.create_group_handle().

11.2.3 Subscriber-Related Subprograms

A subscriber is represented by using dbms_ldap_utl.handle data type. You can create a subscriber handle by using a DN, GUID or simple name. When a simple name is used, additional information from the root Oracle Context is used to identify the subscriber. This example shows a subscriber handle being created:

retval := DBMS_LDAP_UTL.create_subscriber_handle(
subscriber_handle,
DBMS_LDAP_UTL.TYPE_DN,
"o=example,dc=com"
);

subscriber_handle is created by it's DN: o=oracle,dc=com.

Getting subscriber properties is one common use of a subscriber handle. Here is an example:

my_attrs is of type DBMS_LDAP.STRING_COLLECTION
       my_attrs(1) :='orclguid';  
       retval := DBMS_LDAP_UTL.get_subscriber_properties(
my_session,
my_attrs,
DBMS_LDAP_UTL.ENTRY_PROPERTIES,
my_pset_coll
);

11.2.3.2 Function get_subscriber_properties

The function get_subscriber_properties()retrieves the subscriber properties for the given subscriber handle.

Syntax

FUNCTION get_subscriber_properties 
( 
ld IN SESSION, 
subscriber_handle IN HANDLE, 
attrs IN STRING_COLLECTION, 
ptype IN PLS_INTEGER, 
ret_pset_coll OUT PROPERTY_SET_COLLECTION
) 
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can only be called after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also

DBMS_LDAP.init(), DBMS_LDAP_UTL.create_subscriber_handle().

11.2.3.4 Function get_subscriber_ext_properties

The function get_subscriber_ext_properties() retrieves the subscriber extended properties. Currently this can be used to retrieve the subscriber-wide default Resource Access Descriptors.

Syntax

FUNCTION get_subscriber_ext_properties
(
ld IN SESSION,
subscriber_handle IN HANDLE,
attrs IN STRING_COLLECTION,
ptype IN PLS_INTEGER,
filter IN VARCHAR2,
rep_pset_coll OUT PROPERTY_SET_COLLECTION
)
RETURN PLS_INTEGER;

Parameters

Return Values

Usage Notes

This function can be called only after a valid LDAP session is obtained from a call to DBMS_LDAP.init().

See Also DBMS_LDAP.init(), DBMS_LDAP_UTL.get_subscriber_properties().

11.2.4 Property-Related Subprograms

Many of the user-related, subscriber-related, and group-related subprograms return DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION, which is a collection of one or more LDAP entries representing results. Each of these entries is represented by a DBMS_LDAP_UTL.PROPERTY_SET. A PROPERTY_SET may contain attributes—that is, properties—and its values. Here is an example that illustrates the retrieval of properties from DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION:

my_attrs is of type DBMS_LDAP.STRING_COLLECTION
my_attrs(1) :='cn';

retval := DBMS_LDAP_UTL.get_group_membership(
my_session,
user_handle,
DBMS_LDAP_UTL.DIRECT_MEMBERSHIP,
my_attrs,
my_pset_coll
);

IF my_pset_coll.count > 0 THEN
      FOR i in my_pset_coll.first .. my_pset_coll.last LOOP
--    my_property_names is of type DBMS_LDAP.STRING_COLLECTION
       retval := DBMS_LDAP_UTL.get_property_names(
pset_coll(i),
property_names
       IF my_property_names.count > 0 THEN
           FOR j in my_property_names.first .. my_property_names.last LOOP
             retval := DBMS_LDAP_UTL.get_property_values(
pset_coll(i),
property_names(j),
property_values
             if my_property_values.COUNT > 0 then
              FOR k in my_property_values.FIRST..my_property_values.LAST LOOP
                     DBMS_OUTPUT.PUT_LINE(my_property_names(j)  || ':'  
                        ||my_property_values(k));
                    END LOOP; -- For each value
             else
                DBMS_OUTPUT.PUT_LINE('NO VALUES FOR' || my_property_names(j));
             end if;
           END LOOP; -- For each property name
         END IF; -- IF my_property_names.count > 0
      END LOOP; -- For each propertyset
  END IF; -- If my_pset_coll.count > 0

use_handle is a user handle. my_pset_coll contains all the nested groups that user_handle belongs to. The code loops through the resulting entries and prints out the cn of each entry.

11.2.5 Miscellaneous Subprograms

The miscellaneous subprograms in the DBMS_LDAP_UTL package perform a variety of different functions.

11.3 Function Return Code Summary

The DBMS_LDAP_UTL functions can return the values in the following table

Table 11-61 Function Return Codes

NameReturn CodeDescription
SUCCESS
0

Operation successful.

GENERAL_ERROR
-1

This error code is returned on failure conditions other than those conditions listed here.

PARAM_ERROR
-2

Returned by all functions when an invalid input parameter is encountered.

NO_GROUP_MEMBERSHIP
-3

Returned by user-related functions and group functions when the user is not a member of a group.

NO_SUCH_SUBSCRIBER
-4

Returned by subscriber-related functions when the subscriber does not exist in the directory.

NO_SUCH_USER
-5

Returned by user-related functions when the user does not exist in the directory.

NO_ROOT_ORCL_CTX
-6

Returned by most functions when the root oracle context does not exist in the directory.

MULTIPLE_SUBSCRIBER_ENTRIES
-7

Returned by subscriber-related functions when multiple subscriber entries are found for the given subscriber nickname.

INVALID_ROOT_ORCL_CTX
-8

Root Oracle Context does not contain all the required information needed by the function.

NO_SUBSCRIBER_ORCL_CTX
-9

Oracle Context does not exist for the subscriber.

INVALID_SUBSCRIBER_ORCL_CTX
-10

Oracle Context for the subscriber is invalid.

MULTIPLE_USER_ENTRIES
-11

Returned by user-related functions when multiple user entries exist for the given user nickname.

NO_SUCH_GROUP
-12

Returned by group related functions when a group does not exist in the directory.

MULTIPLE_GROUP_ENTRIES
-13

Multiple group entries exist for the given group nickname in the directory.

ACCT_TOTALLY_LOCKED_EXCEPTION
-14

Returned by DBMS_LDAP_UTL.authenticate_user() function when a user account is locked. This error is based on the password policy set in the subscriber oracle context.

AUTH_PASSWD_CHANGE_WARN
-15

This return code is deprecated.

AUTH_FAILURE_EXCEPTION
-16

Returned by DBMS_LDAP_UTL.authenticate_user() function when user authentication fails.

PWD_EXPIRED_EXCEPTION
-17

Returned by DBMS_LDAP_UTL.authenticate_user() function when the user password has expired. This is a password policy error.

RESET_HANDLE
-18

Returned when entity handle properties are being reset by the caller.

SUBSCRIBER_NOT_FOUND
-19

Returned by DBMS_LDAP-UTL.locate_subscriber_for_user() function when it is unable to locate the subscriber.

PWD_EXPIRE_WARN
-20

Returned by DBMS_LDAP_UTL.authenticate_user() function when the user password is about to expire. This is a password policy error.

PWD_MINLENGTH_ERROR
-21

Returned by DBMS_LDAP_UTL.set_user_properties() function while changing the user password and the new user password is less than the minimum required length. This is a password policy error.

PWD_NUMERIC_ERROR
-22

Returned by DBMS_LDAP_UTL.set_user_properties() function while changing the user password and the new user password does not contain at least one numeric character. This is a password policy error.

PWD_NULL_ERROR
-23

Returned by DBMS_LDAP_UTL.set_user_properties() function while changing the user password and the new user password is an empty password. This is a password policy error.

PWD_INHISTORY_ERROR
-24

Returned by DBMS_LDAP_UTL.set_user_properties() function while changing the user password and the new user password is the same as the previous password. This is a password policy error.

PWD_ILLEGALVALUE_ERROR
-25

Returned by DBMS_LDAP_UTL.set_user_properties() function while changing the user password and the new user password has an illegal character. This is a password policy error.

PWD_GRACELOGIN_WARN
-26

Returned by DBMS_LDAP_UTL.authenticate_user() function to indicate that the user password has expired and the user has been given a grace login. This is a password policy error.

PWD_MUSTCHANGE_ERROR
-27

Returned by DBMS_LDAP_UTL.authenticate_user() function when user password must be changed. This is a password policy error.

USER_ACCT_DISABLED_ERROR
-29

Returned by DBMS_LDAP_UTL.authenticate_user() function when user account has been disabled. This is a password policy error.

PROPERTY_NOT_FOUND
-30

Returned by user-related functions while searching for a user property in the directory.


11.4 Data Type Summary

The DBMS_LDAP_UTL package uses the data types in the following table

PK_`=PKؐj?OEBPS/intro.htm\f Developing Applications for Oracle Identity Management

1 Developing Applications for Oracle Identity Management

As of Release 11g Release 1 (11.1.1), the recommended security API for Fusion Middleware application developers is Oracle Platform Security for Java, which is documented in the Fusion Middleware Security Guide. The Oracle Identity Management interfaces described in the current book are not part of Oracle Platform Security for Java.

Oracle Identity Management provides a shared infrastructure for all Oracle applications. It also provides services and interfaces that facilitate third-party enterprise application development. These interfaces are useful for application developers who need to incorporate identity management into their applications.

This chapter discusses these interfaces and recommends application development best practices in the Oracle Identity Management environment.

This chapter contains the following topics:

1.1 Oracle Identity Management Services Available for Application Integration

Custom applications can use Oracle Identity Management through a set of documented and supported services and APIs. For example:


Note:

Oracle Fusion Middleware 11g Release 1 (11.1.1) does not include Oracle Single Sign-On or Oracle Delegated Administration Services. Oracle Internet Directory 11g Release 1 (11.1.1), however, is compatible with Oracle Single Sign-On and Oracle Delegated Administration Services 10g (10.1.4.3.0) or later.

1.2 Integrating Existing Applications with Oracle Identity Management

For new applications, use Oracle Platform Security for Java, which is documented in the Fusion Middleware Security Guide.

An enterprise may have already deployed certain applications to perform critical business functions. Oracle Identity Management provides the following services that can be leveraged by the deployment to modify existing applications:

  • Automated User Provisioning: The deployment can develop a custom provisioning agent that automates the provisioning of users in the existing application in response to provisioning events in the Oracle Identity Management infrastructure. This agent must be developed using the interfaces of Oracle Provisioning Integration Service.


    See Also:

    Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for more information about developing automated user provisioning.

  • User Authentication Services: If the user interface of the existing application is based on HTTP, integrating it with Oracle HTTP Server and protecting its URL using mod_osso authenticates all incoming user requests using the Oracle Single Sign-On service.

  • Centralized User Profile Management: If the user interface of the existing application is based on HTTP, and it is integrated with Oracle Single Sign-On for authentication, the application can use the self-service console of Oracle Delegated Administration Services to enable centralized user profile management. The self-service console can be customized by the deployment to address the specific needs of the application.

1.3 Oracle Identity Management Programming: An Overview

This section introduces you to the Oracle Identity Management Software Developer's Kit. It provides an overview of how an application can use the kit to integrate with the directory. You are also acquainted with the rest of the directory product suite.

The section contains these topics:

1.3.3 Application Development in the Oracle Identity Management Environment

This section contains these topics:

1.3.3.1 Architecture of an Oracle Identity Management Application

Most Oracle Identity Management applications are back-end programs that simultaneously handle multiple requests from multiple users. Figure 1-1 shows how a directory is used by such applications.

As Figure 1-1 shows, when a user request involves an LDAP-enabled operation, the application processes the request using a smaller set of pre-created directory connections.

1.3.3.2 Oracle Identity Management Interactions During the Application Life Cycle

Table 1-1 walks you through the directory operations that an application typically performs during its lifecycle.

Table 1-1 Interactions During Application Lifecycle

Point in Application LifecycleLogic

Application Installation

  1. Create an application identity in the directory. The application uses this identity to perform most of its LDAP operations.

  2. Give the application identity LDAP authorizations by making it part of the correct LDAP groups. These authorizations enable the application to accept user credentials and authenticate them against the directory. The directory can also use application authorizations to proxy for the user when LDAP operations must be performed on the user's behalf.

Application Startup and Bootstrap

The application must retrieve credentials that enable it to authenticate itself to the directory.

If the application stores configuration metadata in Oracle Internet Directory, it can retrieve that metadata and initialize other parts of the application.

The application can then establish a pool of connections to serve user requests.

Application Runtime

For every end-user request that needs an LDAP operation, the application can:

  • Pick a connection from the pool of LDAP connections.

  • Switch the user to the end-user identity if the LDAP operation must be performed with the effective rights of the end-user.

  • Perform the LDAP operation by using either the regular API or the API enhancements described in this chapter.

  • Ensure that the effective user is now the application identity when the LDAP operation is complete.

  • Return the LDAP connection back to the pool of connections.

Application Shutdown

Abandon any outstanding LDAP operations and close all LDAP connections.

Application Deinstallation

Remove the application identity and the LDAP authorizations granted to it.


1.3.3.3 Services and APIs for Integrating Applications with Oracle Identity Management

Application developers can integrate with Oracle Identity Management by using the services and APIs listed and described in Table 1-2.

Figure 1-2 shows an application leveraging some of the services illustrated in Table 1-2.

As Figure 1-2 shows, the application integrates with Oracle Internet Directory as follows:

  • Using PL/SQL, C, or Java APIs, it performs LDAP operations directly against the directory.

  • In some cases, it directs users to self-service features of Oracle Delegated Administration Services.

  • It is notified of changes to entries for users or groups in Oracle Internet Directory. The Oracle Directory Provisioning Integration Service provides this notification.

PKޞ\\PKؐj?OEBPS/pt_app.htm} Appendixes

Part III

Appendixes

Part III presents plug-ins that can be used to customize provisioning in Oracle Collaboration Suite. In addition, this section contains an appendix about DSML syntax and usage.

PKSPKؐj? OEBPS/toc.ncxt Oracle® Fusion Middleware Application Developer's Guide for Oracle Identity Management, 11g Release 1 (11.1.1) Cover Table of Contents List of Figures List of Tables Oracle Fusion Middleware Application Developer's Guide for Oracle Identity Management, 11g Release 1 (11.1.1) Preface What's New in the SDK? Programming for Oracle Identity Management Developing Applications for Oracle Identity Management Developing Applications with Standard LDAP APIs Extensions to the LDAP Protocol Developing Applications With Oracle Extensions to the Standard APIs Using the Java API Extensions to JNDI Using the API Extensions in PL/SQL Developing Provisioning-Integrated Applications Oracle Internet Directory Programming Reference C API Reference DBMS_LDAP PL/SQL Reference Java API Reference DBMS_LDAP_UTL PL/SQL Reference Oracle Directory Integration and Provisioning Java API Reference Oracle Directory Integration Platform PL/SQL API Reference Appendixes Java Plug-ins for User Provisioning DSML Syntax Migrating from Netscape LDAP SDK API to Oracle LDAP SDK API Index Copyright PK+f;ytPKؐj?OEBPS/cover.htm Cover

Oracle Corporation

PKJPKؐj?OEBPS/java_prov.htm Oracle Directory Integration and Provisioning Java API Reference

12 Oracle Directory Integration and Provisioning Java API Reference

As of 10g (10.1.4.0.1), Oracle offers two complementary provisioning products, optimized for different use cases.

The Oracle Internet Directory SDK includes an Oracle Directory Integration and Provisioning user provisioning API, which enables you to manage users and their application properties in the Oracle Identity Management infrastructure. This chapter describes the main features of the API and explains how to use them.

This chapter contains the following sections:

12.1 Application Configuration

Applications must register with the provisioning system in order to be recognized as provisionable. They must also create their own configuration in Oracle Internet Directory using the command-line interface. Java classes exist for viewing application configurations.

This section contains the following topics:

12.1.1 Application Registration and Provisioning Configuration

In order to register with the provisioning system, an application must create a provisioning configuration. After the provisioning configuration exists, the provisioning system identifies the application as directory-enabled and provisionable.

The application must perform the following steps to create a provisioning configuration:

  1. Application Registration

  2. Provisioning Configuration

12.1.1.1 Application Registration

Oracle applications typically register themselves by using the repository APIs in the repository.jar file under $ORACLE_HOME/jlib. This file is provided during installation specifically for application registration. In addition to creating an application entry in Oracle Internet Directory, repository APIs can be used to add the application to privileged groups.

Applications written by customers, however, cannot use the repository.jar APIs to perform application registration. So application developers must use LDIF templates and create application entries in Oracle Internet Directory using LDAP commands.

An application must create a container for itself under one of these containers:

  • "cn=Products,cn=OracleContext"—for applications that service users in multiple realms

  • "cn=Products,cn=OracleContext,RealmDN"—for applications that service users in a specific realm

If an application is configured for a specific realm, then that application cannot manage users in other realms. In most cases, you should create the application outside any identity management realm so that the application is not tied to a specific realm in Oracle Internet Directory.

Whenever a new instance of the application installs, a separate entry for the application instance is created under the application's container. Some of the provisioning configuration is common to all the instances of a particular type and some is specific to the instance. When multiple instances of an application are deployed in an enterprise, each instance is independent of the others. Each instance is defined as a separate provisionable application. Users can be provisioned for one or more instances of this application, so that the user can get access to one or more instances of this application.

The examples in this section are for a sample application similar to Oracle Files. When the first instance of this application installs, specific entries must be created in Oracle Internet Directory. In the following example, the name of this application, chosen at run time, is Files-App1 and the type of the application is FILES. The application can have LDIF templates that can be instantiated if required and then uploaded to Oracle Internet Directory. In this example, the application identity is outside any realm. That is, it is under the "cn=Products,cn=OracleContext" container.

dn: cn=FILES,cn=Products,cn=OracleContext
changetype: add
objectclass: orclContainer

dn: orclApplicationCommonName=Files-App1,cn=FILES,cn=Products,cn=OracleContext
changetype: add
orclappfullname: Files Application Instance 1
userpassword: welcome123
description: This is a test Appliction instance.
protocolInformation: xxxxx
orclVersion: 1.0
orclaci: access to entry by group="cn=odisgroup,cn=DIPAdmins,
 cn=Directory Integration  Platform,cn=Products,
 cn=OracleContext" (browse,proxy) by group="cn=User Provisioning Admins,
 cn=Groups,cn=OracleContext" (browse,proxy)
orclaci: access to attr=(*) by group="cn=odisgroup,cn=DIPAdmins,
 cn=Directory Integration Platform,cn=Products,
 cn=OracleContext" (search,read,write,compare) 
 by group="cn=User Provisioning Admins,
 cn=Groups,cn=OracleContext" (search,read,write,compare)

The ACLs shown in the example are discussed in the "Application User Data Location" section.

The application is expected to grant certain privileges to some provisioning services and provisioning administrators.

When the second instance of this application installs, the following entries must be created in Oracle Directory Integration and Provisioning, assuming the name of this application, decided at run time, is Files-App2.

dn: orclApplicationCommonName=Files-App2,cn=FILES,cn=Products,cn=OracleContext 
changetype: add
orclappfullname: Files Application Instance 2
userpassword: welcome123
description: This is a test Appliction instance.
orclVersion: 1.0
orclaci: access to entry by group="cn=odisgroup,
 cn=DIPAdmins,cn=Directory Integration Platform,cn=Products,
 cn=OracleContext" (browse,proxy) by group="cn=User Provisioning Admins,
 cn=Groups,cn=OracleContext" (browse,proxy)
orclaci: access to attr=(*) by group="cn=odisgroup,cn=DIPAdmins,
 cn=Directory Integration Platform,cn=Products,
 cn=OracleContext" (search,read,write,compare) by 
 group="cn=User Provisioning Admins,cn=Groups,cn=OracleContext"
 (search,read,write,compare)

After the application creates its entries successfully, the application's identity is registered in Oracle Internet Directory. At this point, the application can add itself to certain privileged groups in Oracle Internet Directory, if it needs specific privileges. Table 12-1, "Some Useful Privilege Groups" shows some of the privileged groups that an application can add itself to. Each of these groups exists in every realm and also in the RootOracleContext. The RootOracleContext Group is a member of the group in all the realms

For example, the following LDIF file adds the Files-App1 application to cn=OracleCreateUser, which gives it the privilege to create users in all realms.

dn:cn=OracleCreateUser,cn=Groups,cn=OracleContext 
changetype: modify
add: uniquemember
uniquemember: orclApplicationCommonName=Files-App1,cn=FILES,cn=Products,cn=OracleContext

12.1.1.2 Provisioning Configuration

An application's provisioning configuration is maintained in its provisioning profile. The provisioning system supports three different provisioning profile versions: Versions 1.1, 2.0 and 3.0. The provisioning service provides different service for the different profile version. Some generic configuration details are common to all applications, regardless of version.

Differences Between Provisioning Configuration Versions

The differences between the Version 3.0 profile and the Version 2.0 and Version 1.1 profiles are as follows:

Version 3.0-Specific Provisioning Configuration

Unless otherwise stated, the remainder of this section describes the Version 3.0-specific provisioning configuration. Figure 12-1 shows the DIT in Oracle Internet Directory used to store the provisioning configuration. All the provisioning configuration information is located under the following container:

cn=Provisioning,cn=Directory Integration Platform,cn=Products,cn=OracleContext

Common provisioning configuration information is stored in entries under the container:

cn=Profiles,cn=Provisioning,cn=Directory Integration Platform,
 cn=Products,cn=OracleContext

The rest of the provisioning configuration for an application is located under:

cn=ApplicationType,cn=Applications,cn=Provisioning,
 cn=Directory Integration Platform,cn=Products,cn=OracleContext

All the instances of a specific application type share the configuration under this container. That is, whenever a second instance of an existing application type creates a provisioning profile, all the configuration information under the "cn=ApplicationType" container is shared.

The Profiles container contains the following types of configuration information:

Whenever an instance of an application creates a profile, the new profile is stored as a separate entry under the Profiles container in the following naming format:

orclODIPProfileName=GUID_of_the_Realm_Entry_GUID_of_the_Application_Identity,….

An application must specify the following information when creating a provisioning configuration:

12.1.1.2.1 Application Identity Information

An instance of an application is uniquely identified by the following parameters:

  • Application DN—A unique DN in the Oracle Internet Directory representing the application. This is a mandatory parameter.

  • Application Type— A parameter that is common to all instances of the same application. Multiple instances of a particular type can share some configuration. This is a mandatory parameter.

  • Application Name—This can be separately specified. If not specified, it is extracted from the DN. This is an optional parameter.

  • Application Display Name—A user-friendly name for the application. This shows up on the Provisioning Console as a target provisionable application. This is an optional parameter.

You provide these application identity parameters while creating the provisioning profile by using the following arguments to the $ORACLE_HOME/bin/oidprovtool command line utility, respectively:

  • application_type

  • application_dn

  • application_name

  • application_display_name


See Also:

The oidprovtool command-line tool reference in Oracle Fusion Middleware Reference for Oracle Identity Management.

12.1.1.2.2 Application Identity Realm Information

An application registers for a specific realm in order to provide services to the users of that realm only. An application must create a separate provisioning profile for each of the realms it provides services for. In a multi realm scenario, such as a hosted Oracle Portal scenario, applications must register for individual realms.

Whenever a provisioning administrator for a realm accesses the Provisioning Console, only the applications that are registered for that realm are shown as provisionable target applications.

The application specifies realm information while creating the provisioning profile by using the $ORACLE_HOME/bin/oidprovtool command line utility with the argument organization_dn.


See Also:

The oidprovtool command-line tool reference inOracle Fusion Middleware Administrator's Guide for Oracle Internet Directory.

12.1.1.2.3 Application Provisioning and Default Policy

While creating a provisioning profile, an application can specify whether the Provisioning Console should manage provisioning to that application or not. If not, the application does not show up on the Provisioning Console as an application to be provisioned. However, Oracle Directory Integration and Provisioning still processes this profile and propagates the events as expected.

An application specifies this information while creating the provisioning profile by using the application_isdasvisible argument to the $ORACLE_HOME/bin/oidprovtool command line utility. The default value is TRUE.

An application can configure a default policy determining whether all the users in that realm should be provisioned for that application by default or no users should be provisioned by default. The valid values are

  • PROVISIONING_REQUIRED—all users are provisioned by default

  • PROVISIONING_NOT_REQUIRED—no users are provisioned by default

The default is set to PROVISIONING_REQUIRED

You can override the default policy with application-provided policy plug-ins at run time. In addition, an administrator can override both the default policy and the decision of the policy plug-in.

An application provides the default policy information by using the default_provisioning_policy argument to the $ORACLE_HOME/bin/oidprovtool command line utility.

12.1.1.2.4 Application User Data Location

Application-specific user information is stored in the application-specific containers. If this data is to be managed by the provisioning system, the application must specify the location of these containers during provisioning registration. An application specifies its user data location by using the user_data_location argument to the $ORACLE_HOME/bin/oidprovtool command line utility. The application must ensure that the ACLs on this container allow Oracle Delegated Administration Services and Oracle Directory Integration and Provisioning to manage the information in this container.

12.1.1.2.5 Event Interface Configuration

Applications can subscribe for provisioning events using different interfaces: PLSQL, Java, and OID-LDAP. Table 12-2, "Interfaces and Their Configuration" lists the supported interfaces and their associated configuration. Note that INTERFACE_VERSION is coupled with provisioning profile version.

Applications can use the following arguments to $ORACLE_HOME/bin/oidprovtool when specifying an event interface configuration:

  • interface_type (Default is PLSQL)

  • interface_version (Default is 2.0)

  • interface_name

  • interface_connect_info

  • interface_additional_info

Table 12-3, "Information Formats Supported by the PLSQL Interface" lists the interface connection information formats that the PL/SQL interface supports when it connects to a remote database. All the formats are supported for all interface versions.

Some examples of supported formats are:

   localhost:1521:iasdb:scott:tiger

   localhost:1521:iasdbsvc:scott:tiger
   DBSVC=TNSALIAS:scott:tiger
   DBURL=ldap://example.com:3060/samplegdbname:scott:tiger
12.1.1.2.6 Application User Attribute and Defaults Configuration

An application can specify its application-specific user attributes configuration in an LDIF file. This is supported only for interface version 3.0.

As shown in Figure 12-1, "The Directory Information Tree for Provisioning Configuration Data", the configuration for a particular attribute is stored as a separate entry under the container:

"cn=Attributes,cn=User Configuration,cn=Attribute configuration,
 cn=Application_Type,cn=Applications,cn=Provisioning,
 cn=Directory Integration Platform,cn=Products,cn=OracleContext" 

There is no argument to oidprovtool for uploading this information. The application must use an LDAP file and command-line tools to upload its attribute configuration information to Oracle Internet Directory.

Each application-specific attribute is represented as a separate entry. The following example is for the attribute orclFilesDomain:

dn: cn=orclFilesDomain,cn=Attributes,cn=User configuration,cn=Attribute configuration,……
changetype: add
orcldasadminmodifiable: 1
orcldasviewable: 1
displayname: Files Domain
orcldasismandatory: 1
orcldasuitype: LOV
orcldaslov: us.example.com
orcldaslov: oraclecorp.com
orclDASAttrIsUIField: 1
orclDASAttrIsFieldForCreate: 1
orclDASAttrIsFieldForEdit: 1
orclDASAttrToDisplayByDefault: 1
orclDASSelfModifiable: 1
orclDASAttrDisplayOrder: 1
orclDASAttrDefaultValue: oraclecorp.com
orclDASAttrObjectClass: orclFILESUser
objectclass: orclDASConfigAttr
objectclass: orclcontainer

Table 12-4, "Properties Stored as Attributes in the Attribute Configuration Entry" explains the significance of each of the properties that are stored as attributes in the attribute configuration entry.

Table 12-4 Properties Stored as Attributes in the Attribute Configuration Entry

Property NameDescriptionComments

orclDASIsUIField

Whether this property is to be shown in the DAS Console or not

Not Used in 11g Release 1 (11.1.1). All attributes are shown.

orclDASUIType

The Type of the UI Field: singletext, multitext, LOV, DATE, Number, password

Used by Oracle Internet Directory Self-Service Console only

orclDASAdminModifiable

Whether the field is modifiable by the administrator or not

Not Used in 11g Release 1 (11.1.1). All attributes are modifiable by administrator.

orclDASViewAble

Whether this attribute is a read-only attribute in the Oracle Internet Directory Self-Service Console

Not Used in 11g Release 1 (11.1.1)

displayName

The Localized Name of the attribute as it shows on the Oracle Internet Directory Self-Service Console


orclDASIsMandatory

Whether this attribute is mandatory or not

If a mandatory attribute is not populated, the Oracle Internet Directory Self-Service Console complains

orclDASAttrIsFieldForCreate

Whether to expose this attribute only during user creation

Not Used in 11g Release 1 (11.1.1)

orclDASAttrIsFieldForEdit

Whether to expose this attribute only during user editing

Not Used in 11g Release 1 (11.1.1)

orclDASAttrToDisplayByDefault

Whether to hide the attribute by default under a collapsed section

Not Used in 11g Release 1 (11.1.1)

orclDASSelfModifiable

Whether this attribute is modifiable by the user or not

Not Used in 11g Release 1 (11.1.1), as Oracle Internet Directory Self-Service Console is only for application-specific attributes. Users cannot change their user preferences from the Oracle Internet Directory Self-Service Console.

OrclDASAttrDisplayOrder

The order is which the attribute is to be displayed in the application-specific section

Not Used in 11g Release 1 (11.1.1)

OrclDASAttrDefaultValue

The initial default value for the attribute that is used by the provisioning components: Oracle Internet Directory Self-Service Console, Oracle Directory Integration and Provisioning, Bulk Provisioning Tool

Can be changed using the Oracle Internet Directory Self-Service Console Application Management Page. The Plug-ins or the administrator can override the initial default values.

OrclDASAttrObjectClass

The LDAP object class that the attribute belongs to.

Used to create the application-specific user entries that the provisioning system maintains.


If an application has application-specific attributes, you can specify that the provisioning system manage its attributes defaults. You do that by using the manage_application_defaults argument to $ORACLE_HOME/bin/oidprovtool. This argument is TRUE by default.

12.1.1.2.8 Application Propagation Configuration

Event propagation configuration parameters vary from one profile version to another. Table 12-5, "Event propagation parameters" lists and describes configuration parameters for event propagation.

Table 12-5 Event propagation parameters

ParameterSupported Provisioning Profile VersionDescription

profile_mode

2.0,.3.0

Whether the application is to receive outbound provisioning events from Oracle Internet Directory, to send inbound events, or both. Values are OUTBOUND (default), INBOUND, and BOTH.

Schedule

1.1, 2.0, 3.0

The scheduling interval after which pending events are propagated

enable_bootstrap

3.0

Enables events for application bootstrapping. This specifies that the application should be notified of users that existed in Oracle Internet Directory before the application created its provisioning profile.

enable_upgrade

3.0

Enables events for application user upgrade. This specifies that the application should be notified of users that existed in Oracle Internet Directory before the upgrade. If the application was present before the upgrade, users might already exist in the application. For such users, Oracle Directory Integration and Provisioning sends an Upgrade Event to the application so that the user is handled differently from a normal new user.

lastchangenumber

3.0

The change number in Oracle Internet Directoryfrom which the events need to be sent to the application.

max_prov_failure_limit

3.0

The maximum number of retries that the Oracle Directory Integration and Provisioning server attempts when provisioning a user for that application.

max_events_per_invocation

2.0, 3.0

For bulk event propagation, this specifies the maximum number of events that can be packaged and sent during one invocation of the event interface.

max_events_per_schedule

2.0

Maximum number of events that Oracle Directory Integration and Provisioning sends to an application in one execution of the profile. The default is 25. In deployments with many profiles and applications, this enables Oracle Directory Integration and Provisioning, which is multithreaded, to execute threads for multiple profiles.

event_subscription

1.1, 2.0, 3.0

Defines the types of OUTBOUND events an application is to receive from the event propagation service. The format is:

Object_Type:Domain:Operation(Attributes,…)

For example:

USER:cn=users,dc=example,dc=com:ADD(*)

specifies that USER_ADD event should be sent if the user that was created is under the specified domain and that all attributes should also be sent.

USER:cn=users,dc=example,dc=com:MODIFY(cn,sn.mail,telephonenumber)

specifies that USER_MODIFY event should be sent if the user that was modified is under the specified domain and any of the listed attributes were modified

USER:cn=users,dc=example,dc=com:DELETE

specifies that USER_DELETE event should be sent if a user under the specified domain was deleted

event_permitted_operations

2.0

Defines the types of INBOUND events an application is privileged to send to the Oracle Directory Integration and Provisioning server. The format is:

Object_Type:Domain:Operation(Attributes,…)

For example:

IDENTITY:cn=users,dc=example,dc=com:ADD(*)

specifies that IDENTITY_ADD event is allowed for the specified domain and all attributes are also allowed. This means that the application is allowed to create users in Oracle Internet Directory.

 IDENTITY:cn=users,dc=example,dc=com:MODIFY(cn,sn.mail,telephonenumber)

Specifies that IDENTITY_MODIFY is allowed for only the attributes in the list. Other attributes are silently ignored. This means that the application is allowed to modify the listed attributes of the users in Oracle Internet Directory.

IDENTITY:cn=users,dc=example,dc=com:DELETE

Specifies that the application is allowed to delete users in Oracle Internet Directory

event_mapping_rules

2.0

For INBOUND profiles, this specifies the type of object received from an application and a qualifying filter condition to determine the domain of interest for this event. Multiple rules are allowed. The format is:

Object_Type: Filter_condition: Domain_Of_Interest

For example:

EMP::cn=users,dc=example,dc=com

specifies that if the object type received is EMP, the event is meant for the domain "cn=users,dc=example,dc=com".

EMP:l=AMERICA:l=AMER,cn=users,dc=example,dc=com

specifies that if the object type received is EMP, and the event has the attribute l (locality) and its value is AMERICA, the event is meant for the domain "l=AMER,cn=users,dc=example,dc=com".


12.1.1.2.9 Application Event Propagation Run Time Status

The Oracle Provisioning Service records a user's provisioning status in Oracle Internet Directory for each provisioning-integrated application. This is described in the Deploying and Configuring Provisioning chapter of Oracle Fusion Middleware Administrator's Guide for Oracle Directory Integration Platform.

12.1.2 Application Configuration Classes

The oracle.idm.user.provisioning.configuration.Configuration class enables you to obtain provisioning schema information. The oracle.idm.user.provisioning.configuration.Application class enables you to obtain metadata for registered applications. These classes are documented under the package oracle.idm.provisioning.configuration.

The Configuration class provides access to application configurations. To construct, a Configuration object, you must specify the realm. For example:

Configuration cfg = new Configuration ("us");

Then you use Configuration class methods to get one or all application configurations in a realm. You must supply the LDAP context of the realm.

The Configuration object is a fairly heavy weight object, as its creation requires access to the Oracle Internet Directory metadata. Best practice is to create a Configuration object once during initialization of an application, then to reuse it for all operations that require it.

The Application object represents an application instance. Its methods provide metadata about a registered application in the infrastructure.

12.2 User Management

When Oracle Directory Integration and Provisioning or Oracle Delegated Administration Services invokes a provisioning plug-in, it passes information about the user being provisioned. A deployed application can use the user object to modify the user.

The user management provisioning classes provide the following operations:

  • Create, modify, and delete a base user

  • Create, modify, and delete application-specific user information

  • Search base users

  • Retrieve user provisioning status for applications

This section includes the following topics:

12.2.1 Creating a User

Creating a user in the Oracle Identity Management repository consists of two steps:

  1. Creating basic user information in the specified realm. This information is referred to as the base user.

  2. Creating the application-specific user attributes, or footprint. This information is referred to as the application user.

The combination of the base user and application user in the repository is referred to as the Oracle Identity Management user. Some methods create only the base user and other create both components of the Oracle Identity Management user.

The minimum information required to create a user is a set of attributes representing the base user. The attributes are in the form of name-value pairs. These user attributes are represented as Java objects using the class oracle.ldap.util.ModPropertySet.

Some user creation methods require you to specify the DN of the entry that you want to create in the Oracle Identity Management user repository. Other methods do not require the DN. Instead, they construct the Oracle Identity Management user using the metadata configuration information from the Realm in which the user is created.

If the creation of the base user and application user succeeds, then the creation method returns an IdmUser object. You use this object to manage the attributes of the base user and application user.

12.2.2 Modifying a User

Modifying a base user in the Oracle Identity Management repository results in

  • Modifying the base user information

  • Creating or modifying application user information

You must supply the following information in order to modify an Oracle Identity Management user:

  1. The user's DN, GUID, or IdmUser object reference

  2. The desired changes to the base user attributes, represented as an oracle.ldap.util.ModPropertySet

Some user modification methods modify only the base user attributes. Others modify the application user attributes as well.

12.2.3 Deleting a User

Deleting a base user in the Oracle Identity Management repository produces the following results:

  • Deleting the base user information

  • Deleting the application user information

To modify an Oracle Identity Management user, you must supply the DN, GUID, or IdmUser object reference.

As result of this operation, the base user and the application user attributes are deleted.

12.2.4 Looking Up a User

The lookup methods provide two lookup options:

  • Look up a specific Oracle Identity Management user using GUID or DN

  • Look up a set of Oracle Identity Management users using a search filter

In order to look up Oracle Identity Management users, you must provide the DN or GUID.

The output of a lookup method is one of the following:

  • A single IdmUser object

  • A list of IdmUser objects

12.3 Debugging

Set UtilDebug.MODE_PROVISIONING_API mode to enable debugging and trace information. If you do not specify an output stream for the log messages, they are written to standard output.

The following snippet shows how to set UtilDebug.MODE_PROVISIONING_API mode and specify an output stream:

Import oracle.ldap.util.UtilDebug;
        FileOutputStream logStream = new FileOutputStream("ProvAPI.log")
        …
        UtilDebug.setDebugMode(UtilDebug.MODE_PROVISIONING_API);
UtilDebug.setPrintStream(logStream);

12.4 Sample Code

The following code example shows how to create, modify, and look up a user and how to get user provisioning status for an application.

UtilDebug.setDebugMode(UtilDebug.MODE_PROVISIONING_API);
…
Configuration cfg = new Configuration(realm);
    try {
      debug("Connecting...");
      InitialLdapContext ctx =
          ConnectionUtil.getDefaultDirCtx(hostName, port, bindDn, passwd);
      debug("Connected...");
      UserFactory factory = UserFactoryBuilder.createUserFactory(ctx, cfg);

      // Create 
      ModPropertySet mpSet = new ModPropertySet(); 
      mpSet.addProperty("cn","Heman");
      mpSet.addProperty("sn","The Master");
      mpSet.addProperty("uid","Heman");
      IdmUser idmUser = factory.createUser(mpSet);

      // Modify 
      mpSet = new ModPropertySet();
      mpSet.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_REPLACE,"sn",
            "Heman The Master");
      mpSet.addProperty("givenName","Master of the Universe");
      factory.modifyUser(idmUser, mpSet);

              // Lookup         List users = factory.searchUsers(Util.IDTYPE_SIMPLE, "Hema*", null);
        ….

        // Get user provisioning status for an application.
              Application app = cfg.getApplication(lCtx, "Files", "FilesInstace");
        String  status = idmUser.getProvisioningStatus(app);


      // Another way to get user provisioning status
              String userDn = idmUser.getDNn();
        String  status = ProvUtil.getUserProvisioningStatus(dirctx, 
            Util.IDTYPE_DN, userDn, app.getType(), app.getName());
    } catch (Exception ex) {
      ex.printStackTrace();
       //
   }
PK7-PKؐj?OEBPS/img/oidag025.gifJ!GIF87a?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ /hРA J_|71_РA !|?}'߿}ӗO,h „ 2l!Ĉ'Rh"ƌ7rQ`?߿۷}߿| H*\ȰÇ#JHŋ3jȱǁ80/߿/߿8`A&TaC!F8bE1fԸcG'p`~_ _'p "Lp!ÆB(q"Ŋ/b̨q#ǎ 'p`}ӷ|O@ DPB >QD-^ĘQF=0@/߿ O~ <0… :|1ĉ+Z1ƍ;z,/?~Ǐ?~c|?~Ǐ?~G>~Ǐ?~Ǐ}Ǐ?~Ǐ=Ǐ?~Ǐ?zǏ?~Ǐ?~Ǐ?~Ǐ?~1Ǐ?~Ǐ?~c?~Ǐ?~|?~Ǐ?~G>~Ǐ?~Ǐ}Ǐ?~Ǐ=Ǐ?~Ǐ?z? 4xaB 6tbD)VxcF9v1Ǐ?~Ǐ?~c?~Ǐ?~|?~Ǐ?~G>~Ǐ?~Ǐ}Ǐ?~Ǐ=Ǐ?~Ǐ?zǏ?~Ǐ?~Ǐ?~Ǐ?~1Ǐ?~Ǐ?~c?~Ǐ?~|?~Ǐ?~G>~Ǐ?~Ǐ}Ǐ?~Ǐ=>裏>裏>裎●,h „ 2l!Ĉ'Rh"ƌ7rQc? @~/_>O_>~? 4xaB 6tbD)VxcF9vd08p߾ O|/߿|/?~O@ DPB >QD-^ĘQFO|(0|˗O@_>@~ H*\ȰÇ#JHŋ3jȱB~ o~/@|O@ DPB >QD-^ĘQFO|(P߾˗/_>}}'0|,h „ 2l!Ĉ'Rh"ƌ7r`>'p?}8_|/_~ '0? <0… :|1ĉ+Z1ƍ;.ԧO_|ѣG=zѣG=zhp>G=zѣG=z#A~ϣG=zѣG=zQ`|ϣG=zѣG=z_~ ѣG=zѣG=v_}}ѣG=zѣG=bܧO|~Ǐ?~GqǏ?~Ǐ?~q>Ǐ?~Ǐ5|?~Ǐ?~c~}OǏ?~Ǐ?~x_~ Ǐ?~Ǐ?VG}Ǐ?~Ǐx_~?~Ǐ?~D}>&Ǐ}G}G}GO,h B'p "Lp!ÆB(q"Ŋ/b̨q#ǎp>=zѣG=zqc|<>ԷϣG=zѣG=z/?ѣG=zѣG/ϣDyѣG=zѣG+b|:ѣG=zѣG3/_> O_|4א_|_yѣG=zѣGOA~w0|o>} /|OG=zѣG=zd`>8_˗/ӷA $HP|GP`˗/O?$XA .dC%NXE5n`>'p` '0߿~O@ O~ o /?} H*\ȰÇ#JHŋ3jh| /_|_>~'p  O| o|˗O߿|>~ H*\ȰÇ#JHŋ3jX|o/_|8`A'p`>O~ o_>}? 4xaB 6tbD)VxcF-'p`>~ H&08`A&TaC!F8bE1fԸ#E}  <0B~ ? 4xaB 6tbD)VxcF9R0@8`A&TO|O@ DPB >QD-^ĘQFϟӧo߿|:vرcǎ;vرcLjQ|:vرcǎ;vرcLJؑa|:vرcǎ;vرcdž!|;vرcǎ;vر#Cuq;vرcǎ;vq};JԷcǎ;vرcǎ;vLO_ǎرcǎ;vرcǎױcEuرcǎ;vرcǎb|:vرcǎ;vرcǁ#|:v쨣:ꨣ:ꨣ: 'p "Lp!C'p "Lp!ÆB(q"Ŋ/b̨q#GqQ>}9rȑ#G9rȑc|8rH0>9rȑ#G9rq>}9r,/_?9rȑ#G9r1>}9r9rȑ#G9rȑ|8rP>9rȑ#G9rQ|8r0>9rȑ#G9r_}9r|/_?9rȑ#G9rQ>9FG9rGqGq@'p "Lp!Æ СC:tСC:tСC:tСÄ9tСCСC:tСC:tСC:tСCsСC"ԧϡC:tСC:tСC:tСCСC:ToC:tСC:tСC:tСC ϡC:t_~:tСC:tСC:tСC:Ã`>:tx_>/_>~˗/?9tСC:C9C9C)} H󗏟|_|/_>˗ŋs/_> ̇0~˗?}'0?~_|'0?~߾|ӧ/>/?O߾|˧ŋ/^xŋ3o?>} O`_>x>} o߿|!ܧ? /뷏_>G0| ?~۷}߿|/?~/ <0… :|1ĉ+Nԗ/_}70߿|/_|/_˗@~gѢE ?_>˗/_>}ӗ_>~70߿}_>̗@~/?70߿|'0|_>O@ DPB >QD%'p>o`#8ПǏ_ _}'p "Lp!AO`7|?}(_> 7П> O߿| O߿|߿| ߿|O@ DPB >QD#O| O߾_˗O_?}|'?~'p "Lp@~ ?/߿|/_|7_>}o ?}'|>~O _>}/'0|_>O@ DPB >QD#O|8П|ۗO˗/߾ӧ_>_|'p "Lp} ӗ/_7p@~ϟ|7_>˗߿|˗/o`>˗|_>} '0|˗߿| ? 4xaB 6tbD)V`>O@ DPB 20'p "Lp!C6lذaÆ 6lذaÆ 6lذ~ ? 4xaB 6t|O@ DPB 5lذaÆ 6lذaÆ 6lذaC ? 4xaB 6tp|O@ DPB >QD-^ĘQB~ӷoƍӧo_|6nܸqƍ7nܸqc~mܸq~mܸqƍ7nܸqƃ۸qƌ۸qƍ7nܸqƍ۸qƍmܸqƍ7nܸqƂmܸqFmܸqƍ7nܸqƁmܸqFmܸqƍ7nܸqmܸqƂ۸qƍ7nܸqF۸qƍqƍ7nܸqƍqƍoƍ7nܸqƍ-,h „ 2l!ĄE1bĈ#F1bĈ#F1bAE1bĈ#.ԧ/bĈ#F1bĈ#F1bĈ 1bĈ#FP߾#F1bĈ#F1bĈ#FO_Ĉ#F1CE1bĈ#F1bĈ#F1>}#F1bĈ1bĈ#F1bĈ#F1bćE1bĈ#F/#F1bĈ#F1bĈ#6_Ĉ#F1bDE1bĈ#F1bĈ#F|"F1bDEA <0… :|1ĉ+Z1#BiԨQFӨQF5jԨQFiԨQFQF5jԨQFӨQF OF5jԨQF!ӧQF5"ϟF5jԨQF5:OF5jT/F5jԨQF56ϟF5jԸP>5jԨQF5j\/_?5jԨ}5jԨQF5jԘ_~5jԨQCiԨQF5jԨQ#|4jԨQFӨQF5jԨQFY,h|;H0|O@ DPB >QDg_}/?hѢEY\/_~_>~ gѢE-Zh"} ˗?}C_'P߾|˗|o_~O_>}gѢEs/_>~˗|_|/_70_/>~ O_|˗E-ZhѢE _A~/o?'0ȏ>} _~/߿|? 4xaB 6t(P>_~|?~_}O|'0_?'0|/Ç>|Ç>|_|`_|߿~O`>ȯ`?~O`>_>>|Ç'P`?/@ /_||_/~_>O`>  <0… :|1ĉ'p>|0@/߿8߿__/߿8`A&TaC87_0@߿|O߿/߿_/,h „ 2l!Ĉ'RT`>'p?}O`>~˧_'0|'? _>_O@ DPB  08P_>70|/_? 70߿|'P_?/O`>'0,h „ 2l!Ĉ'RT`>'p?/|7O`>G_| '0|/| H*\ȰC80ӗ/߾8_o`/_>~˗/>O`>O`>$XA .dC%NP|O@ DPB >QB} ? 4xaB 6tbD)Vx"? <0… :|1D8P,h „ 2l!Ĉ'Rh"F} ? 4xaB 6tbD 'P?$XA .dC%NXE/cƌ3f̨>}8`A&TaC!F8bE1fԸcGA9.dI'QTeK/aƔ9fM7qԹgO?:hQG&UZ0 ;;PKHO!J!PKؐj?OEBPS/img/oiddg003.gifC/GIF87a?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU, H*\ȰÇ'p "Lp!ÆB(q"Ŋ/b̨>$XA .dC'p "Lp!ÆB(q"Ŋ/b̨Ѡ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7n4ƍ7noƍ7nܸqƍ7oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ۸qƍmܸqƍ7nܸqFmܸq|6nܸqƍ7nܸqA}6nܸqc>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7nd@'p "Lp!Æ>"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!BT@'p  ;/| w?w`| H*\ȰÇ#JHŋ3j4| )'1_۸`>7nܸqƍ7nܸѠ>~ Է/??~O ?~_| د?~O_|ӗ/˗ϟ@}H07nܸqƍ7nhP/| O| 7P?~+O?_>?~۷}o#|6nܸqƍ7nܸqA}6O`>o| '>/_|o/|  <80?$XA .dC%NXE5oc>_>/|O |?7p_}߿|/,h|8`A&TaC!F8bE1fhPO`| O@}7'?~70߿|O`>6oƍ7nܸqƍ7oc>_>~˗O>~ ̷/_|˗_A~ϟ|/_~˗߿|O`>6oƍ7nܸqƍ7oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ۸qƍmܸqƍ7h6 O@ DPB >|D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!B O@ DPB >|D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!B O@ DPB >|,h „ 2l!Ĉ'Rh"ƌ O@ DPa|-\p…8`A&TaC!F8bE1fԸcC}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;fO> <0… :|1ĉ+Z1ƍ;z0'p "Lp!ÆB(q"Ŋ/b̨q#ǎ+O@ H*\ȰÇ#JHŋ3jȱNj ,h „ 2l!Ĉ'Rh"ƌ7r"?O@ DPB >QD-^ĘQF=fO~ H*\ȰÇ#JHŋ3jȱnj˧Ǐ?~Ǐ?~1_|>~Ǐ?~ǏǏ?~Ǐ?~Ǐ?~Ǐ?~?~Ǐ?~Ǐ?~Ǐ?~Q|,h 2l!|8`A&TaC!F8bE1fhP>$XA .dÇ'p "Lp!ÆB(q"Ŋ/b̨Ѡ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7n4ƍ7noƍ7nܸqƍ7oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ۸qƍmܸqƍ7nܸqFmܸq|6nܸqƍ7nܸqA}6nܸqc>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7nd@'p "Lp!Æ>"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA$| 惘_|A| B"D!BDADADAT@'p g` ,ϠA | 4hРAO@ DPB >QD-^ĘQA}&`>˧/|˗ϟ@}/˗?~/W0~˗?O_|/_>Ob>7nܸqƍ7nܸѠ>~| /_'|O`ϟ>/@~O |}_O`>~Ioƍ7nܸqƍ7O>~O`>_>~/| /O` 'P~뗏@~'P>O|  ? 4xaB 6tbD)VxcF0@__߿|/߿|O?~o@߿߾|ۗ߿|/߿ ? 4xaB 6tbD)VxcF/@}/| O?'0|ӷO`|'0?}7'?~_O`>$qƍ7nܸqƍ q ܗO>?}O`>ϟ|˗O>~/_>~˗o?_|˗/_ӗ/_?擘ƍ7nܸqƍ7n4ƍ7noƍ7nܸqƍ7,h „ 2l| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"D,h „ 2l| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,D!B| B"D!B"D!B"D,h „ 2l| B"D!B"D!B"ĂA"D!"D!B"D!B"D!B,O@~,h „ 2l|8`A&TaC!F8bE1fh@},h „ ˗o… .D? 4xaB 6tbD)VxcF92ԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_Nj8`AO@ DPB >QD-^ĘQƌ㈑|,h | H*\ȰÇ#JHŋ3jܘQ_|1O@ D? 4xaB 6tbD)VxcF3˗#F~O@ /_>$XA .dC%NXE5n̨/_>Ǐ@}qȑ#G9rȑ#G #|q/_>9rȑ#G9rq|8b/?Ǒ#G9rȑ#G9ϟ?}G/_>}Q_|9rȑ#G9rȑA~ 8P,h „ H? 4xP_| H*\ȰÇ#JHŋ3jh`>O@ D|  $XA .dC%NXE5n`>O@ DP | O@ /_>$XA .dC%NXE5n0'p "L(|O@ /_>$XA .dC%NXE5n`>'p "LH`>8`A˗? 4xaB 6tbD)VxcF1˗/_>˗/_?Ǒ#G9rȑ#G9*/_}/˗Oǁȑ#G9rȑ#G˗#F8P_|9rȑ#G9rȑBq̨OGȑ#G9rȑ#Gџ?Ǒ#G9rȑ#G9r1|8rȑ#G9r`?$XA .dC8@}'p "Lp!ÆB(q"Ŋ/bQ_>$XA .dÇ'p AO@ DPB >QD-^Ę1>~5jԨ`> ˧QF5jԨQF QF P_|5jԨQF5jԨ>~5jԨ`> ˧QF5jԨQF QF P_|5jԨQF5jԨ>~5jԨ`> ˧QF5jԨQF QF P_|5jԨQF5jԨ>~5jԨ`> ˧QF5jԨQF QF P_|5jԨQF5jԨ>~5jH? ԗ/,h „ 2l!Ĉ'Rh"ƌӨQFc/_>5jԨQF5jHP?˗OYW0_|o`|1a> ˧QF5jԨQF `-w1_|/߾ӧ1a> ˧QF5jԨQF `>˗ϟ@}˧߾| Ǐ}ǯ`70|̧1a> ˧QF5jԨQF `'|o?`>? o||O@ <BO@ DPB >QD-^Ę1>~ ˗/ '0| '0| W0_| _?}˗OF1ԗ/F5jԨQF5j$F 'P_/߿_> 7P` O'p "$_O@ DPB >QD-^Ę1>~ +@~}O`>+`o>~itC}iԨQF5jԨQFi4?}o`O`>`|/_|74:珡|4jԨQF5jԨQ#A}4jԨQc|8@}'p "Lp!ÆB(q"Ŋ/bQ?5jX`>  <0… :|1ĉ+Z1cD}4>ܗ/>Ө1!|,(? 4xaB 6tbD)Vxcƈit~]̧Q#|8`A$XA .dC%NXE#㧱~O_}O>~|/_>?}(1?5jԨQF5j8Q? '0_'|O`>o|?~4JOF5jԨQF5NOc| 70_>~ G_>70|ӷϟFiԨQF5jԨQƉilA0O?~/߿/?$XAO@ DPB >QD-^ĘQA}62엏@ } _O`>/|70ƈmܸqƍ7nܸqFmlo_| ̧/߾O`ӧ߿|/_~ _|mƍ7nܸqƍ7n4F6nH07nܸqƍ7nhPmܸ`>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7n4 }8`A&TaC"D!B"D!B"D!"D!B`>!B"D!B"D!BbA} B"D"D!B"D!B"D!"D!B`>!B"D!B"D!BbA} B"D"D!B"D!B"D!"D!B`>!B"D!B"D!BbA} B"D"D!B"D!B"D!* }8`A&TaC"D!B"D!B"D!"D!B`>!B"D!B"D!BbA} B"D"D!B"D!B"D!0 <0 :|1?$XA .dC%NXE5O@ DP|-\p…8`A&TaC!F8bE1fԸcC}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcG}uرcǎ;vرcǎ;vԗ/_ǎ;vرcǎ;vرcFӗ/?uرcǎ;vرcǎ; ~ 8P,h „ 2l!Ĉ'Rh"ƌ7r"| <0… :|1ĉ+Z1ƍ;z`>O@ DPB >QD-^ĘQF=^O|8`A&TaC!F8bE1fԸcG'P>$XA .dC%NXE5ncF O@ DPB >QD-^ĘQF=j/_}?~Ǐ?~ǍǏ?~Ǐ?roǏ?~Ǐ?~?~Ǐ?~Ǐ?~Ǐ?~? 4xaB 6t@$XA .dC%NXE50 <0… :|1?$XA .dC%NXE5oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ۸qƍmܸqƍ7nܸqFmܸq|6nܸqƍ7nܸqA}6nܸqc>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7n4ƍ7noƍ7nܸqƍ7oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ H?$XA .dÇA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?'P?$X`> /_| 4/A 4/?$XA .dC%NXE5c -|6nƍ7nܸqƍ7n4|O>~O_>~ӷ/?O_>}`/ϟ| o_|ۗ|6nܸqƍ7nܸqA}0/@~ϟ|_>~O`>'_}/@~o_>o߾ _>mܸqƍ7nܸqFa70?O |/߿|?/'p`?~O oO`>8`AO@ DPB >QD-^ĘQA}00@/߿_>~@߿ _}//߿ ,,h „ 2l!Ĉ'Rh"ƌ 1@}/| '0߿||O ?/>~70ӷ| ̧17nܸqƍ7nhP?ӗ/?O`>|/?W_|/_>~˗|ϟ| '0|6nܸqƍ7nܸqA}6nܸqc>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘ?$XA .dC%NXE5oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ۸qƍmܸqƍ7nܸqFmܸq|6nܸqƍ7nܸqA}6nܸqc>7nܸqƍ7nܸѠ>~7nܸ17nܸqƍ7nhP7nܘƍ7nܸqƍ7n4ƍ7noƍ7nܸqƍ7oƍ7qƍ7nܸqƍ qƍ۸qƍ7nܸqƍ H?$XA .dÇA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"D"D!B<D!B"D!B"D!BXP?!B"ăA"D!B"D!B"DO@ DPB >|,h „ 2l!Ĉ'Rh"ƌ O@ DPB >? 4xaB 6tbD)VxcF9vdH#I4yeJ+YtfL3iִy'gN;yhPC5ziRK6ujTSVzU`@;;PKH/C/PKؐj?OEBPS/img/oiddg005.gif.;GIF87a?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIMO}'p_| ̗/_>}'P ?̗/_}˗o|0@8`A&T!}߾|/_>}˗/>(ۗ/>/? O ȏ_o@~'p "Lpa}'߾|/_>}˗/> ?˗/? ̗_|`>(߿(,h „ 2L/_O@}'p_>O߿|'0߾O_~/_ 6l|˷/> ̗O|'0)̗O|'0_̗`|'0_̗aÆ &ԗ?~˧O|/ ̧/_>/ ̗_|/|/_5lذaÆ ȯ߾|ӷ/_?/|˧0_> ̧/߾ |8`A&T|ӗ@O|'0_%ܗ@˗߿|W0_>|+/_Æ 6L/@~'П>/߾ ̗/_> _|/@}G0_>˗`| 6lذa}_|#/߿|˗|O@ |O>~(,h „ 2/_}g0_>˗|'P? ̗o|_|(?7Pۧ߿ <0…˷̗`|`>O}O`|0@߿˧@ ? 4xaB *O_|+/|˗/>S/|_~ӗ/5lذaÆӗ/_|#/߿|_| #/߿|˗_|#/_~'0_5lذaC˗_|#/߿|/_˗߿|/_> ̗ |'?O@ DPB /|ӧ/?/_|'0_> ϟ '? 4xaB o`| ϟ|˧_|K/?/?~˗`|3o_̗aÆ &o`|O?} O߿|˧П˗O`|/|'P̗aÆ 6l/O@}'p_~+/|_~?˗aÆ 6}/߿~ ܗ߿|˧_>O_/|G0_>˗`| 2dȐ!C˷O`?}߾|/_A  |(P,h „ 2$/_|ӗ/>˗O_?O@} o_| ̗O|(P߿ ߿~o@}  <0…˗o~O}'0_> ?˗/>˷O |O o_7P>$XA .dC%NXE5nG!E^08`A&TaC!08`A&TaC!F<`>'p "Lp!ÆB(q"Ŋ/b̨q#ǎ? )r$ɒ&OLr%˖._Œ)s&͚6o̩s'Ϟ> *t(ѢF"Mt)ӦNB*u*UNZ'UjժUWjժU_O>~U鏟>}UUo>}U]/_>}6˧O_|U5/_|˗_UO@}'p A8`A&TaC! ̗o~˷? 4xaB 6tb~ׯ_?~1bĈ#F(P_>~ o_>~ Hp?$XA .dC <0… :|b| (0_>$XA .dC˷`?O@ DPB >/>/,h „ 2l!ć'p |8`A&TaC!Fܗ`? ?  <0… :|q_>$/_?$XA .dCO@'p "Lp!ÆBO~엏? 4xaB 6t>} H_>~ H*\ȰÇ`? ? 4xaB 6t"|8`|8@ H*\ȰÇO@O@ DPB >_>~ H_> H*\ȰÇ!O@ DPB >O~엏,h „ 2l!ĆO@O@ DPB >q_>$/_?$(,h „ 2l!}8 |8`A&TaC!:̧`?  <0… :|1|8p| Hp?$XA .dCO'p "Lp!ÆB|/~̷? 4xaB 6tbO~O@'p "Lp!ÆB/?/?$XA .dCO@'p "Lp!ÆB_|ׯ?}ПD%J(Q!|ׯ_?~OD%J(Ѡ|ׯ_}'QD%Jp_>˧O_|뗏B%J(QĄ/_>}_|$J(QDӧ|ӗ/_>'QD%JXP>˷A)'QD%JDO?׏|$J(QD˷`?~G_~%J(QDwПKOD%J$Aӧ?Gp?}8`A&TaC!엏A~/bĈ#F|ӗP_>E1bĈ˷?} 1bĈ#FH_~C/߾#F1"D_?3/bĈ#F_>~ S/#F1bDKȏB}"F1bĈ O?~ 1bĈ#F/_?-엯_Ĉ#F1>} [/#F1b[OCE1bĈo?} 1bĈ#Ft/>1䗯_Ĉ#( H>$8П˧? 4xaB 6tp>} k/>!B"ākȏ_~A"D!oC"D!B_}{O?!B"~9ϡ| B"D˷?}"D!Bl/߾AܗD!B|П>}!B"DO"D!.엯D D!B| | B"D ?}˷"D!Bp_~Q`| B" R }8`4hp_~ H*\ȰÇQ?}˷"D!Bxp_>q| B"Dq ?~"D!BP>XP>!BbA} bA} B"D ?~ ˷"D!Bh_} | B"D?} "D!B(_~ ?} B"DѠ?}"D!B|/?x_~!B"}A4ȏă"D!㗯ă /}~ kذaÆ aÁ5lHp_> 6lذ!~+/_ ۗ_ ˷O}ǯaÆ ?~ ׯaÁׯaÁo_|CaÆ ׏_? <?}CaA~ /_|!D!B"4`>/?$XA~ӗ/_~߾|8`A˧O_|}w˗O?~w~~w~~Ww _B}.,o_Bp… ӗP_ |.$/_[p… 0߾ ˧_~ ϟB}.\pASo…S/_ O>}-\pBK/_ ۧp_ 0 .\|˷paA}p@~ <0ƒO!| Էoa>~ o!|-\pB-̷oBS/ ӷP߾ .\ | [`>~ [p | [p…o!| oa>~ o!|-\pB-ԧoBS/ ۷P .\`| [} [p | [p…o!| Էoa>~ o|-\pB-ԧoBS/ ӷ0 .\|? 4hp_wo}wA;(P_ԗ@~paAo_A .\0|˧oƒ!ԗoB;/_ .\| oB+/߾ ˗~[p… ܗA}-\0_~۷p~O_>}-\pB+/_ ˧A[| /_ .\0|/_~ *ԗ/>}p!~'p`>$XA *wp_|ۗ/_ ˗O>}[a|80 <0BǏ?}[0a|ӗ/_~ "ܧ`>O@ DP…˗/? ۧO>~ "O`?~Ǐ!C ߾|ǐBǏ!C Ǐǐ!C ӗ/_>}2\o>}1dx_>_> 2dȐ!C 2d_>1dȐ!C2dȐ!CC/A 2dȐ!C 2d(P?1dȐ!C 2dȐ|ǐ!C cȐ!C /}1dȐ!C 2dȐ~ǐ!C 2dȐ!C [C 2  H*\a} #aÆ 6lذaÆS/_Æ 6lذaÆ 󷐟 6TП <0… : <0… :|!| 1bĈ#F|o_|"F1bĈ0_#F1bD1/bĈ#Fѡ|1bĈ#FT/~"F1bĈP߾#F1bĆ=/bĈ#F1a>~1bĈ#FL/CE1bĈ#.|#F1bĈ/_Ĉ#F1bB} 1bĈ#F0_E1bĈ#/}#F1bĈ/#F1bĄE_Ĉ#FQDO,H0?$XA .dC_#F1bĄEO_Ĉ#F1b|" /bĈ#F |1bĈ#FxP߾1bĈ#Fo_DE1bĈ#/~"F1bĈ  |#F1bĈX_#F1bāE,_Ĉ#F1bA}"/bĈ#F>~ 1bĈ#F_> 1bĈ#FH_1bĈ#F/~"F1bĈ>}#F1bĈ(_?$X A}8`A&TaC1}!B"D僨0?!B"ĄAT/?!B"ĂAT/?!B"DATOD!Bb| .ܧ"D!B`>"D!BX_> "D!B!B"DAt/D!B@~ :"D!B>~"D!BO?"D!H O@ /B"D!B"D!~"D_>"D!B"D!~"D_>"D!B"D!!D}"D!B"D!B˗/߾|"D}˗oB"D!B"D(߾|ۗBӷO_|C!B"D!Bӗ/_|!D|˗O_?"D!B"D|/_>~"DO_>}ۗ/_?"D!B"Dxp_|/_>~ H}C!B"D!B}C!~珟|"D!B"D!B3/>̗ϟA}!D!B"D!‚3/>̗ϟA}!D!B"D!B3/?O~!D!B"D!BC/?ܗB}"D!B"D!~!B |"D!B"D|ˇ!B!oB"D!B!A#H A Ǐ O@ DPB  ԗOa}_>~>|Á%ÆK/Ç>|`>~ {ؐ_=|Ç㧐_ [oÇ>|P | {P=|Ç O|2o>}>|S/ [OÇ>|P | {0=|Ç O|2o!|>|S/ [/Ç>|P | {0=|Ç O!|? ӧ? 4xaB 6t_~ {ؐ_=|Ç˷P [Ç>|`>} {_~ {Ç ̧O>}Oa>~>|CSÆ)Ç>|h_~С| {Ç䗯~=t/_}>|ÇK/Ç%̧Ç>|xP_~|Ç>|HP_~|Ç>|H_>}!|Ç>| }|8`A ˗!B"D!Bԗo_?Ӈ!B?~C!B"D!B?!B?~C!B"D!BO@~ H'P> H*\ȰC8,h} ,h „ 2l0> ? 4x`? <0… :t诟?&Ç>|~=|_?>|C{P~8`A&TaC!F8bE1fԸcGA9dI'QTeK/aƔ9fM7qԹgO?:hQG&U4?0'p "Lp!ÆB(q"Ŋ/b̨q#ǎ? )r$ɒ&OLr%˖._Œ)s&͚6o̩s'Ϟ> *t(ѢF"Mt)ӦNB*u*ժVbͪu+׮^ +v,ٲfϢMv-۶n+w.ݺvͫw/߾~,x0†#Nx1ƎC,y2ʖ/cάy3Ξ?-z4ҦONzu|㧑?֬/XFo_|Ko}?}/_>O_>}Yݗ/߾}`>O`o|߾}? 4xaB 6tbD)VxcF9v\/>ԗ'P`O>_8`A&TaC!F8bE1fԸcGO@'p`Ǐ_>0@߿|'p "Lp!ÆB(q"Ŋ/b̨q#ǎ O@'P`_O ?/߿| H*\ȰÇ#JHŋ3jȱcB'p A}(0_|/>}˗?}O_|O@ DPB >QD-^ĘQF <0… :|1ĉ+Z1ƍ;z/~/,h „ 2l!Ĉ'Rh"ƌ7r|8| /_|8p8`A&TaC!F8bE1fԸcLJ'p |(0_8pO@ DPB >QD-^ĘQF`?? | /_/ <0 :|1ĉ+Z1ƍ;6̗~˷?O |O`_ <0… :|1ĉ+Z1ƍ;6/>~ӗO~뗏@~_ϣG=zѣG=z`>'p?O@_(0| H*\ȰÇ#JHŋ3jȱc~KO~_>}'0G=zѣG=z"|O_|˗O>~ӗ/_O@ DPB >QD-^ĘQF=~RH%MDRJ-]SL5męSN=}TPEETRM>UTU^Śa@;;PK$2ME..PKؐj?OEBPS/img/oimad019.gif@GIF89aE@@@򠠠000vvv;;;``` pppPPP,,,XXXgggJJJ<<sH@tCE @3jxE„A-bk Ǘ0c\-*@T17JѣH@2'\YP@XjB֯`*ٳ\]˶-nʝ;.ݻxJ߿*Lˆ=㘌Kl02˘̹s.˞CzoJ^ͺְcoy-(o}$7߻}.[8㫍#_.Z9癝C.Y:뉭cX;y/W@HѠSQ,@85؆ۤcE4`3R`#NऄXA@D.YW!S9TB@+qa+=#) q 4 OZ%MbD08 4KGSDE@D1(M<g:'2(ЌT9Lw9 (XQ"C 0d R|cHCh(PH\)*@GS*a') *Ī8O$6CC$>'fC#ifJED ?R-8S$˖n(l`Ƃlр 4@6EP!Q$@$" S*͸b Gt!$ai2r@-@:J̩*҅WA0IsWF ]oH 7OP 3AEEgB9\-#<R)]HH@ ɳDD5ETlA,H AU]J}E} nx&8!/?.[Mn._o.zn:.{nC߮;;.<o<_n7 GO {@&S up:&aزN%ɁEHєQ\Pp>*T0 \>YFP1 N'X"{@%@L\0; C 7XK1aЈyԭ@@qS܃D%T.Mx+(@#qB)q ]" V+ r7 ˸D>zg=$FflrĈR M|1AYO|D GdiW#g!zD1c)L&"TҔ:yHxJy`I=<'yҩN𰳝y'<#yR>ɜ}9g9'P;(BͧЅeD#RT~h4김r46hkB*d!)JMҕ6.}OKcڙ4:0ylS)Pӡ&&mkB44  ʭFU@qƽ@j`v^6Y"#U2Lbє #Aō X(HcsɳMufH& Eus2LUE߼U+^-N5EfQ UU8rQ2Z) B&0uLDpt6 Nrz 8& \ԭ%]jPN+d6&- O-:9(Y!@%`@h,Z!>BN݋ZJUT(子TM ĉ210_-"pnmhV~)dmbf9+8ЎPdX5,P] (CXȂ J c-ښ„ؒ@1ejI% 1v<+MddL)UM6r;i eJhD%ٔd"l`@ b>X~Qi)a/ Ǖi<,L) Y%, PCDtb"tly,L"IǡV%rnH(!2fΆ0\UG/478Ex=ģ=jU#'zF 72ĺfV fGYx4(%/2K`>F^l0.̈́QvoBEP c XV'amAx8Iks7,n=UIFZhN4bBdV ֳ>s=.^aR.ۄh9;͢nMݤwwҽ_3?|oO?F}?gO_~c_&o~_ {c"W7uI7 0zPG+ +t5KLTUH} @ p({,8@5KƁP@E%au Pu'| 8z -zЀW@zO8|XR F[E4 $,WAu%$NG$ex#d7YG0&)MhzG8z@L `P(z/x( "%^pi2d H]v /e4d'X ' B1DLHUK*X,Ohp HU81( z zЇ~ap)`/ fsezm2E*a\eG@&;(Xz` ɈȂ͸P89؂ӘPS v6B.d#-V(ˠF,93ܶ!t6EP7'>IgJYTTkDMfJH !0/^,Z)H| @Q X B8zy ۈ@g`E;`uE[riz/fFZ3M61hB)Eق `L)ǘrR' HHC+CIG34;!ُL3*U7iETȉ G( {IQA R"w"rS$&8hP*Gp!!C:)`~PE`>x Kl)6Z{+*P`II@_`#zC?vA*GOТLZ~N:O0TZw\ šѥ^j~%!QYZfz412'PJo '$W`/I z|*HU񐧃J|jDF(GR!ZI:mʩa4G*ybڪ}pf0jzzqg*zrjjmAm*i`Zz`3­Y *X1qz*ڮᬂ`[Zz* =1t { kz j@0 cCP!k ;j {,+P1[ { <&rF0 M0aP.k;[g 4Z^Ea@dOGAns2:[p2x3۷VqK>m{D0Zہjcw}fAskh7CpndqkqQ˺}bd;yq Y;{  q[FKKtꭒ 빒1kƪ꽎a*̪!򪾙aװBʼAtg7Abǽ!yljMhg±!&§Y7t'üC؁«)@. ] Pg鷴S@T06ujhg-Jːd=fWIR7׳lqW{sC ) R# Ӡ\6a%Q |㘾`%$M*(n%+1q|)9h4/tD0\2{zlR 1qF#&Ic]4&oF"/dg"l9Ƞp`5aR?r3&,$ 6N, -**Ŝ+ }˷{̜!Q7"Й) }3C0 g,T=L6;bBB2WcY##.N"uv) D<.Fq[*43:!.`vc_ߠH ć5ry fH_&E6Q DI,L}Vے:=i VrVM C*0}`a.D8<=2 M&,UGLyWm/vab& ZUpBc_-+m%!]fnq 2fzc^愾gDE~'O~z^~邗zِɈR xzАznz*8NO^zd)0扄RȂh{0W슎(@ĸ9ޓY Ї zYi)xAg^ӸX~ўK鎄9(oۈ@O'JI"{*BwIXH}W')8oB((.z < G9h<4 K6P79rE> @/ qȂ#?>99?  PpRȂ>''(W$i M$-X"r1 )PXAH0L3QIMNT2\&#A) ElFǤ8o8, >T!#%')+-/135' R `TTj T"S7/ ;<<(:68,ƙP((4޺212ק*`tD&TaNRP!A/STRH xh ƍƔY!S*gXN9fh#V (3F:Q T1cV"p@(8@ 0_R;wQ1 ko_K6lHA1O&V8f)]iҜ/~2p Vq1VMӐh ǖ= gh@wR4p0Dr) 0 5ov HV|>wyKvdD$8?%ֿnĄN#YF>bɀ\#O@,6Oޣ@C`'QLF"K.P44p)D  42@Ϳ#\m SMiIa Fz䡳'&dRؾ\P"P=ј (Vd %93AǍAIGQ]**9TaU&ҝ,Y kn*^Fz @tO "G ҏ{/, o*T. ," /~.d2D`P B!U N 1M `eAq6t!~$ CKPEAFLL<( @xL#i* 6N<V6"e^yiHS ]""$M,9̈[Tp$iL$Eis (h@M)K"4cLI0F\EIt;IP#BpNغNuy13@Јatr2 )PGO24C`7* kioCM3Z(S vņbBgĀBb.`f)Om #]hGCŅ/Dk.c"`Yv{FЧ.22ch+F/ #j"$ΒG.$6+L!-*cpMo_O%L!%DJ0gN)~NO*^ATmiPDF&$H@$ං0 nN0 ~ki̋(+0oh"ģŠ444 6g*OBX.(f-Iպ ,eb%*V1uX$4 < 8L"8,h0* 9L0-!0/a"ƌ3!27">LnD^@2t444g&3uLtR0A&n78O9-܊h75A4KHP; )Hc)^+$T ⒌I.WhARJADz [t[O5q!4; (`nPѾ|QE,saH]MbhcD{pJG[P[+!Uu6guV|xL`h6!!Di!BXfbfƛUkM5kH8634dlU#c6o+ab@p^?',O#έ" ""-H h!"ǾaC! xxC.,hiD'!N"Qq停j1Pqh 'n!4A#7yB& 7!"b৮DDfgBY_Fc7S9HQA$My+\*d1C#^P^y # ŃnB&B}K^5Z6JY.D3C.xK?:vM:Ud `#epö<"+(6;.4!UXw&bBpbJf{oeB^E\K?VA3}9'L[f`:* \/q_1**:H;|x;#rx,sHx؈_B{#E⺈*HDUg⩈A{%O1 bj,ś-ce&nƌagP.եcBbr7X|5j}֩$prARJr8ULzHPU ;jɩf |$afhrAS9:(99|9]L|R'%B.*v#0( @k RG!A[ViCƾ1ëŅC2zk"L¸빏7̺; (=ݬć1vCs|c@D(W-|?qwY>czh`ysD*\.B˷4%\%Q ;楢=f$f/) 0<} a11<Ľq>!{xq毒ֱ#¢\Sc1#[T63a-Bfx-U޳i;Rj~&4]q~rpr-u!99-(L & -wj޷jK{/,SAdL&riiV3jfYX.}ʮDF9Gyio$8jJ? hs)F*^ER]jAjP<*CheEI*("&*.26:>BFJNRVZJ.iQjj9E=HH@D( x.H(:\)] #'+/37;?C7q @4lx `4E""H͛ B"L{8Rt)ӦN+LPl)ꁀsp,ٲfR&8V&)Ne7h޾~p_(Q+w"Zʖ/ K$+o\32HNz"s0h{7i/Yw&1QF[wΛ xȾ)[18GG(.~JUV&ę]q"k$4&_UU`6IX8rBT4'VXQSO8XKA0$ev.aX`X(EĘ9r+j)yPgD(m4#OLB]VAA`g( c2Ixz3hcD ť XZ ^YKD˗<BgR0Q١QC*GyL*DzQa/b#tA|**|sVkKR &tjULYT}z(">k\XcMC_hk[r Y Ѯa_pFW i%@ʢ|z (6aXcqD2@8`"H5dվ(# . -RKZ(9Wv! "Qr`n-*-¼)jw"$iv&0=4t0#$+y@UO8-iΗ]soqǦ%w)/<[R>">KQ3wgND|OV1M]NfX&6U^uF^#֖RħFfEU%CL8.LF|)_ L@uYZK( GP{9Vv]2`KvIE]`x KpQ"Al)j (Y:YB҈(Ba ,p" +˥N$]h~i0*059ȟZD  A7-bL^(\HCLVSA&:;ݎૺ]B;7m{;7<8 n#< _8C<8+nc<8;<"9k<*_9[<29kn<:9{k@:ыn#=J_:S.C=R:իnu?Z:׻<`;n\h_;v @P $`FvO7ǻޑބ=*  )@Rw'OqxC~ 9O@&?s0 (X=;`zgtG=a/+HW(|ʗoyGeGQ0+~񏟂\*@_̧>or(7/ʭ^ qʱUY@%`M _ r`y@ ^ _ xޡ@P`Q^`d@TM @^ ^6] `>!`a ^ !1Fha $ Z^!2!M` !!E"FH5 Fa n"B +n*},>).-6˵\P@q@ ua$c^j@2aꉡ'RT`@TT]$P@T:jYr@T̢1&@2-FcA7c p1a`cBB8'Q j>"@! D#;Z1"2Jb$$/m@̢"M,r@/6@?&$d h!D |Q*eʭd2Bx@JM0Yɩc6f"E ^q .1ޤD(*L6ZX%ccJ@蕥Υ6 8#Z%4dH"@h4^.bbF&Y2,2t"z :e 6Ag"%&UI"&f:2m-!sZp0zcf]w&H"f[wZ]ݞ"%v q٥&~&gDVɦ_#_ae`1&xꭞ"rUax:(|gI4b{ho2($h B2]Va%g^g2 6*⋖0v F"^g~U(zj:\ge$If%}a=\(ʍdVa"fVj;.ij!i"f&Arf]XN$"*6) N^f㤪dJ(y#dy*L~厺r!1^ސ'dBj&7B!푦뽠'y"&I^]~"'jc%P*|榰6^e^z$!9ރ+q^Pa淖c^it(nBa@,,"gj),%"-z'.! qlf˲#In"M,;;Vlʦ?B˒硞IJedNjvbJA˦f͆$2@qɒƬmy+qb-o^&hPfi-r7-,ށ-޾81wjl@ bmй*ԡ$Ɱc۩Ml͕lub]n١.n̙˱u_\$/I`Z\ܲ!ޜ뢜a ̡ٞ;/)j !%o6§ fV ,f% 26/ 0!):gZpq+OJ>pBV}y^ `na! +r)!t(i7B1̟2&%Z*a^b+2!!ʡwjqB%b!'v)#R$rZjg%jo)>6`*-1f;Hc2>@HF&+PN`B.,d>.n'ZR5pL)c1D TV,vcFF*#rdWzf=( dO,7^$k5 P2O!?F-2؅2!RM`i,n+sٖ NZe[6CSf2 '~6.hgj.n.j3)BUI_ﵦni?w (1L/(Pk\@K416ᨉ2uĥ'jpqe/S2 a~tVCVhF2tHs6ah]}R#Z ,H4 VЦOk#"S+Q\R t"V_B@;b=Z$R%ae#2除 ?#eua2/&h5aS6 ~vxO%dvz'OvgFN啦4^*ivPsim]>tT6bn_:67 j.bn066"&[cb4}Hkm1zZ.q+=8_u{1hoBkt391ni^2"l)6w}Oln-7-2@澱. i3 `8@**jj-lnm3uW ں0@8ʞ-8g^ѫ,kx$^'Զy,~ߝ3(/&n-f^ގ;9\.]U@/~2ܦz.'Y>nd:%qsͮϡz{@+3{;C{KS{[c{ks{{{3 ;PK>"A@PKؐj?OEBPS/img/rsaseal.gif GIF87a@sssZZZBBB999)))Z{!99{1Z)s{B!1RsccRkƜR9k)sR1k){k9Z1J)scJބZs{޵1֔sƥskB{ƜνֽƄkέ)k)JB,@pH,Ȥrl:ШtJZجvzxL.zn|Nx'~ 10# 1| "" $||?ye? }#{?#"$$|a676653=11|"'ϋ{܀ \{='& ?&# A*G0˞O$3K"Xĩ*J$G 2kPԿi]i8I1272VH&8IΞX& n ,Hs$|*h]5Yy:fMD`HMKҲNX@.w9XH%8gmI0$8?Բ`G4!v֮Z eD(C*`nU*=\B0kG#4g\ b(# 0[7^z|@7ee! `: ?ps ׉S@(Yn ނƇ& T >' Z7@j |'3 a %F xx i4I8uE`L+fGV 1]Ç"Kn@H:EEɇHxW@MO8pt9 AZyZ*)Ddy!Q@dpj갛@JxML$ >rC&M +_I I6,2k? "B,1>j i%b1 @G;D Ѽr=ȪR$x%]2Vi3|{ 統 `@ 1@Cz4-fN74[pP+lRI֊gA5^pB(*!rĚĿ2nH4 ϙj-l593ܝ|& lVܕId @# `ˊ<1p""MnGޜp»p ssÜI;^>ɬ#ㆽ%BbUa$ (DĆ0 J#1uD1؛Xv2w4ωeXC ) 8P c"x Z!$eϲX 0?J>r ^c [XS"±}y 33`p) ȧ@GOPrÍ0 vhwQ*!A"|BWȜ*"b 0BT& \!A޵3)Q!'UwXIA2wp,!1D+a]8@)W+B'@s]e),=`XA:HC0`̥%1,.}GȉQ fiWҲL" ]5Ae2pA:<{ȱQG ]sKШq7'O@= !5PA)q\r  v /t0-a?CkMt\ܑ:JցzU]CB6pLPt5G,#Yg{lNǴ}p\Ը՜B+ $H@T1ڌj'U%P x  !kX T; :\(X&05(Em VS8_'`z/UBoZHն^T27Q@دPG #*L8Ԯ nxף6=7 وO %ctqt` YI(^0x(s6#& (@!&B)GwQA Zp^WX@Bh6`,ҜVX`.]픜dHґsgʵv]uZ^FeAщdUVA|E4i>vm\[^%թF_XE8YPF/>  )]@2.l itH3 `$@T`tV$>rK@ ?,< R \PP ߞ5 Z`` =U[g!~p"]mzA7Y]Ĭ NJ`NhOp/B;PK| PKؐj?OEBPS/img/oiddg015.gifj2GIF87a?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣA'P 'P? O@ @ @(`?(~'P ~O@ O@ @ ?(? <0… :L_(?('P O@ O@ @ `?(`?'P ~'P? O@ @ @O@ DPB &ׯA O@ O@ O@ O@ O@ O@ O@ O@ O@ O@ O@ O~'p "Lp!ÆÇ>|pa~>|Ç Ç>|_?>|Ä{Ç>\د>|B8`A&TaC!F8bE1fԸcGA9dI˗~ /'O}$H?8`A&T| H_~ ,X@}8`A&T`> 0|~cH_> 2d_cȐ>~ 2dȐa> 0@˗/ ǐ| 2dȐ| ǐ!A}2dȐ!|/a70߿~ǐ| 2dȐ| ǐ!A}2dȐ!|/a|}˗/?cȐ!C [CcȐ!C cȐ!Ä1dȐ!C1dР>~ 2dȐa> 2d_> 2d_> 2 }8`A&T`> #_|!B2dȐ!C2dhP? 2d0? /|c_> 2d_> Ǐ!C 2珡|70"!C 2!CcȐ!C [_|70"!C 2oa~2$C 2dϟB%G0? /,X_> 4hРA `~4h A} 4hРA 4h0?gp`>߿| /A 4hРA g`~ 4h>~ 4hРA 4ϟA380?7 4(_> 4hРA `~4h A} 4hРA 4h0?gp?}o }˗A3hРA 4hРA ϟA ϠA 4hРA3HП? 4hРA/,h „ !CcȐ!C cȐ!Ä1dȐ!C1dР>~ 2dȐa> 2d_> 2d_> Ǐ!C 2~ ̗/_~1L/C 2d/C 㧰_>} ?1TÅO|1L/C˗~ /> ǐ!C)ܗ/Áǐ|.O| ϟ|1/C/_߿}2/B2,| |/߿~O_|˷߿|O@$(_~ _>'0߿|G $H AO|o`? $HP| A $HP?O>ӷ_>~O`>o_70|/_AG}/_| /? $_> $HP`|/_?}˷A $8_> A $A/|70߿| '?/|'0߿| (P| (P~ (_|O@ۗ,/_ /|_>˧` `+X`+H`>߿|/߿|/߿Ǐ_߿|/߿8`> ׯA /A A#H A_>}(? ,/A;xA}ϟ@}oۧ_>/߿|/|o߿|;o_3_|#oA?˗?~O_>˗o|A Ǐ!C 2O@ DP~'p "LpA2dhP? 2d0_>$XA 'p} <0…[CcȐ!C S_? O}/,h „ oa~2$C 2dϟB1d_|+/C 2d/~1dHP? 2d0?c0!|!C 2oa~2$C 2dϟB1d_1dȐ!C-CcȐ!C S_? "!C 2o? Ǐ!C 2!C ǐ!C ǐ!C1dȐ!C1dȐaB2dȐ!C2dhP? 2d0? 2L/C 2d`>$XAK0a„ &/a„ &/_„ &L0| &LhP &L0a|&L0a%L0a„ ˗0a„K0a„ &/@&L| &L0a„%د /a„ &L00a„K0a„ &/~%L>~ &L0a„%_ &D/_„ &L0| /a„K0a„ &/?%L0!B&L0a„ K(_? &,h „ O~2d_> 2d_cȐ>~ 2dȐa> ǐ!C1dȐ!C1dР>~ 2dȐa> 2d_> 2d_> Ǐ!C 2!C ǐ!C ǐ!C1dȐ!C1dȐaB2dȐ!C2dhP_>$XA .4/>$XA > 4xaB O@ Dh@~,h „ ܗ/_>} H* <0… 8?8`A&TaC˧~:tСCϟC:t谠|3_?:tСCСC:4/_| ϡC:ta~9t?6/_>}СC:t`~:th_>:/_>}СC:t`~:th0_>~:t/_|СC:tСC ˗ϡC˗/>:tСC:t80_|9t?СC:tСCO@$XA /_>} .\p… .\p…8p,h „ ˗/ .\p… .\pB80,h „ ˗/ .\p… *o… O@8`A&TH_|-\p… .\0a~.\P| <0B˧o… .\p…p…ۗ/_>~[p…˗/ .\p… … / .\_?~ӷp… .\pB[pӷp… _|-\p… .\? .\H_|.\p˧o… .\p… .\_|.\pB˧o… .\p… .\_|.\p˧o… .\p… .\_|.\B |O@ DPB >Q?/_| 擘obBП|!̗/_~_|ۗ/>M8qĉ˧O`>M8џ?˧O|w0@+_~@~7qD81| 70@}ۗ/?}?o_|ۗ@~O|%ׯAӗp_70|o`_'"ĉ ˧O`> ߾}Ǐ?~߿}o߿|/߿|o?~8p~/_>} #H| ?'0AO@ DP~-\p@/_|o`_>~_>O`K_˧`˗| / o… *… /> o`O }_>O`K_?˧Ϡ~;`o`_ .\_? .\8_|3O}O_?O߾'0| O%B̧?'P_80@~/߿~/| H*\ȰC'0|˗?/_|˗߿| /|˷/Ä˧`?}`>˧o |O_| ̗/_>~>|Ç˧ÇBӷÇÇ>,/_>}>$/_|./_>} =|Ç>||=|C˧Ç>|Å7_>˗|>|X_|9a|˗/_?>|П?$XA ˗O} '_>*TР~/_>} Sp|/| *T0a~*T| O| ϟ|)TP~"/_>} /_~O?~3ϟ>?}SPBPB˧O`} '_>o> *ׯ„˧O|/?~o? /|_>SPBPB˧O~/|_>~8`Aׯ_„˗O_O뗯~/_| &L_~&L0@/_|3O }%L0!A%L8_|'0߿~'P}/_|/|/a„ "_„ &/_>}O`>/a„ 0!AW0_>?70߿|70_„ &L0a„ ˗O߿}/|˗_„ J(_||/߾||߿}_>_|'p "Lp!Æ ˧ϡC:4/_|:tСC:d/_>}:tAСC:tП? @ @˧o@ O@O@ O@ O@O@ O@ /_>} H*\ȰÇ+@ _~ ؏_| @ _~ @(`?(_~(`?'p ˗/}˧O>~"D!B"$/_|˷!B"D!B~!Dp|O@ DPB ˗/>~sСCϡC8P ?$XA .dؐ?? 4xaB 2aÆ'p`>$XA .dР? <0… :|q |O@ DPB O| H*\ȰÇO@$XA .d`?? 4xaB 6t|1bĈO8`A&TaCa|=|Ç O| H*\ȰC{0_~>|!C˗Ç>lدa?}>|C{Ç P`~'p "LpaB$XA O@ DP„ H_~ ,(_?O@ DPB8`A&T(|,h „ &O@W`A+8P?$XA .4C &!C 2oa~2$C 2dC &!C 2!CcȐ!C cȐ!Ä1dȐ!C1dР>~ 2dȐa> 2d_> 2d_> Ǐ!C 2!C ǐ!C ǐ!C1dȐ!C1dȐaB2dȐ!C2<د?1dȐ!C1dȐaB2dȐ!C`~ǐ!C ǐ!C cȐ!C [د?P@~ H*\h0? 2L/C 2d/~1,د?1/_|cXCcȐ!Ä1T/_>~ cp| ǰ`~P`|`> ǐ!C c>1,!Á-Â%|O|ӗO~ӗ/~>}P`> 2d_> O|ӗ/_?/@}1T/~1dHP?/߿|/?~/??}_'p ,X` ,XP| ,/|/?/߿|o_ ` ,XP>~ ̗O`| '0 '߿| /|+X`> ,X` /_ G0|/|/,X? ,X`W |˧_>ӗ/_>o`ۗ_+X` ,X@ ,X_>O>}`˗`/,h B%,/߿}'0@}'0?߿}/_K0a„ ˗0@~'0|'0??&/_„ P˗| /_~|˷O`>%<_„ &L8_ ˗o|˷O~?}Kp| &$د?%L0a„%<_„ &L8_ &L0aB /a~!/a„ /_B%L0aB | H*\h_cX_?cȐ!Â!C ǐ!C ˷_? >~ C!C1dC &a|cÃ-ÂC_|c0CcȐ!Ä1,/| cx_cȐ>~ _>~'P_>}ۧO`~˗?}'_|㗏|2d0| '0|˗O|_>~ ԗO?}14/B2,_B߿|o_>_/?_o߿|O@+X` ,X@ ,(0_>'0}/?O|`+X` _A '0|/_}O``A,X` ,XP| /| '070|/߿| $/_ ,X@} ̗O`>O_| '0}'0| /| ` ,X`+X|O`>'_/߿ /,H_> 4hР>~'0| ?}O`>O`>o߾3h0? 4hРA3h`| '0@}/| ?}4h| 4h? |O|˗?}O |/߿|˷O`> ϠA 4h@ ,/| ԗ?}o`>ӗ/_4h_> 4_?gРAϠA $?$XA  o… .4/~-4د?-\X_|-\`> .\P| .\pAo~!oa|'0ApB-\pB-$/_|[h… [دP/| o…[p…[H0_[0… [دPO`>O_|_|_}o|.\p@̗O`>} O_|˗_|/_?}/_W`W`O`}'0|o߿|_~,XP`> ,X` /_/߿|/?~/|o|_ W` ,(P ˗/_~o_>o`O` ` ,X`+X`|O`>_>o`>o_+X` _W0>}'_'0| H| 4hРA ϠO߿| ̧/_|'0| Է/_?gРA ϠA̗߿~o~o`>3h`> 4hРAg|_>ϟ'0@}'0@~48_> 4hР>~ ̗`>~'P_˗o| '0A3hРA 48_>˗/?O_|˗@}˗o|3hp?8`A>~"D!BC!B!B"<ƒ!BP?"D!B!D!Bˇ!B/B!د?>~"D!BC!B!B"4!!د?>~"D!BC!B!B"D|!CB"D!|"D!BC!B"D/C?!BB!? 4xaB[p… ˷_? o… .4… ./… .\h_ &o… .4… ./… .\h_ &o… .4… ./… .\h_ &o… .4… ./… .\h_ P .\`> .\P| .\pA.Lد?-\p…[p…[p… ˷ПP>$XA .4,h „ П <0…O@W`A+8P|,h „ " <0B8`A&T0!ׯ ,h „ 2l!Ĉ'RدXbŊ+VXQb~*VXbŊ+Vџ?$XA .dC%NXE5nG!E$YI)Ud ҟ?-[lb~Zlٲ~E_˖-[دkٲe˖_?('P ׯ_?'P? O@ ׯ_~ O@ @ _~ @(`?(_~(`?'P ~'P~7P ~O@ O@o@ @ @@8p(`?'P ~'P~7P ~O@ O@o@ @ @@ ?(?ׯ('P ׯ_?'P? O@ ׯ_~ O@ @ _~ د(П(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?NO@ DPB >QD-^ĘQF=~RH%MDRJ-]SL5męSN=};;PKwo2j2PKؐj?OEBPS/img/oiddg004.gifGIF87a ?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU,  H <0… :|1ĉ+Z1ƍ;z`>'p "Lp!ÆB(q"Ŋ/b̨q#ǎ/O@8`A&TaC!F8bE1fԸcG˗/? O@ DPB >QD-^ĘQF=N/_}'P>$XA .dC%NXE5nѣ||'p "Lp!ÆB(q"Ŋ/b̨q#ǎ%'p࿁'p "Lp!ÆB(q"Ŋ/b̨q#ǎ!O H*\ȰÇ#JQ,h „ 2l!Ĉ'RhA7p`?$XA .dC%NDO,h „ 2l!Ĉ'RhA7p ,h „ 2l!Ĉ'&䧏"E)RH"E)R`> ? 4xaB 6tbDG"E)RH"E)O@'p "Lp!ÆB(qbB~(RH"E)RH"Ł8p`?$XA .dC%NTOE)RH"E)RXp| <0… :|1ĉ H"E)RH"E׏"E)RH"EQH"E)RH"EH"E)RH ?})RH"E)RH"|(RH"E)R$OE)RH"E)R0?)RH"E G"E)RH"E)""E)RH"EQH"E)RH"EHq_|o"|O@ 3h_>3h_ 4hРA O,h „ 2l!Ĉ'Rh"|0>O>~0_|è0A~ '0| a8>1bĈ#F1bC}/_>'_|˗ϟ|#O | ܗo>>~O|/@}˧>~o_} O_>}?}>1bĈ#F1b|o|O __>_>_>~ }O@'0|_>~O`>'߿| 

~O`>o`_>~ӷ,h ‚'p "Lp!ÆB(q"Ŋ/2|70|O@(0@`>_߿|(_O@ /߿߿|/߿|/߿/?$XAO@ DPB >QD-^dƇ }_ O>+o?}ϟ}_|O?_> _>_>_|O ?>1bĈ#F1b#D~O_|?}O_|G0|˗?'p_>}?}O_>}7_˗o}?}/_|0>>$XA .dC%NXEaĈb>1b|OF1bĈ#F1#F0bĈ!?}1bĈ#F1bĘF1bĈ#C~0bĈ#F1bĈ1?1bĈ#FaĈ#F1bĈc>1bĈ#F È#F1bĈ#|0bĈ#FӇ#F1bĈ#FaĈ#F12#F1bĈ#FÈ#F1bdOF1bĈ#F1#F1bȐ>1bĈ#F1b#F0#0b ~8`A&TaC!F8bE#F1bȐ>1bĈ#F1b#F1bĈ!?}1bĈ#F1bĘF1bĈ#C~0bĈ#F1bĈ`> 4xaB 6tbD#O@ DPB >QD-^dП <0… */>:taA$XA .dC%NXE5n\/_>~9rȑ#G9rȑ#G!˗G9rȑ#G9rȑ#GǑ#G9rȑ#G9r|qȑ#G9rȑ#G9r/_>~9rȑ#G9rȑ#G!˗G9rȑ#G9rȑ#GǑ#G9rȑ#G9r|qȑ#G9rȑ#G9rdO>}˧O~9rȑ#G9rȑ#G'p A$XA .dC%NXE5nc~ (,h „ 2l!Ĉ'Rh"ƌ7rѢ> <0… :|1ĉ+Z1ƍ;z`>'p "Lp!ÆB(q"Ŋ/b̨qc~Ǒ#dž(? 4xaB 6tbD)VxcFO|8`A&TaC˗C:tСC:tСC:tСCO8`A&TaCСC:tСC:tСC:tСC'_|sСCϡC:tСC:tСC:tСC˷}˗/C:tp>:tСC:tСC:tСC"̗/ ̗/_>:tB:tСC:tСC:tСC:D0o@~,h „ 2l!Ĉ'& <0… :|1ĉ+ZX|o@$XA .dC%NDO,h „ 2l!Ĉ'Rh||O@ DPB >QDQH"E)RH"E˷? <0… :|1ĉ H"E)RH"E˗_|H"E)R8>)RH"E)RHq>? 4xaB 6tbDG"E)RH"E)0'p "Lp!ÆB(qB~(RH"E)RH"EӷE)RH"EH"E)RH"EG"E)RH"A~(RH"E)RH"EQH"E)RH>)RH"E)RHa>)RH"E)䧏"E)RH"E)RDE)RH"EH"E)RH"EG"E)RH"A~(RH"E)RH"EQHa>˗E(R萟>)RH"E)RDE,h „ ǐ!|a| 2dȐ@~2dȐ!C 2dȐ!C 2dȐ!C cȐ!C O_|˗ϟ| /_|˗@}˗߿|cȐ!C cȐ!C 2dȐ!C 2dȐ!C 2!C 2_>} _> ϟ@~O||!C .䧏!C 2dȐ!C 2dȐ!C 2d0? 2d_>߿|/_|_>_>8`A&T ?} 2dȐ!C 2dȐ!C 2dȐ!C1dȐ!C /'0|(߿Ǐ_@O@ DP‚1dȐ!C 2dȐ!C 2dȐ!C ǐ!C |_|~˧@~/|_>2dȐB~2dȐ!C 2dȐ!C 2dȐ!C cȐ!C /_|˗}O_| ˗/߾|/?/| 2dp!?} 2dȐ!C 2dȐ!C 2dȐ!C1dȐ!C 2dȐ!C 2䧏!C 2dȐ!C 2d!b!b!O@ DPB >QDQH"E)RH"EH"E)RH ?})RH"E)RH"|(RH"E)R$OE)RH"E)R0?)RH"E G"E)RH"E)""E)RH"EQH"E)RH"EH"E)RH ?})RH"E)RH"|(RH"E)R$OE)RH"E)R0?)RH"E G"E)RH"E)""E)R"(" ~8`A&TaC!F8bE#F1bȐ>1bĈ#F1b#F1bĈ!?}1bĈ#F1bĘo@~,h „ 2l!Ĉ':ԧ? 4xaB 6tbD)Vx!@},h „ 2l0_>:taA~ H*\ȰÇ#JHŋ3jܸ_|8rȑ#G9rȑ#G9B/?9rȑ#G9rȑ#GǏ#G9rȑ#G9rȑ#Dȑ#G9rȑ#G9r_|8rȑ#G9rȑ#G9B/?9rȑ#G9rȑ#GǏ#G9rȑ#G9rȑ#Dȑ#G9rȑ#G9r_|8rȑ#G9rȑ#G9B/?9rȑ#G9rȑ#G /_> <0… :|1ĉ+Z1ƍ;z0'p "Lp!ÆB(q"Ŋ/b̨q#ǎ)O@8`A&TaC!F8bE1fԸcG8P ,h „ 2l!Ĉ'Rh"ƌ7r"? <0… :|1ĉ+Z1ƍ;z0 H*\ȰÇ#JHŋ3jȱnj˗Ǐ?~Ǐ?~Qc|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~|?~Ǐ?~ǎ}Ǐ?~Ǐ?~Ǐ?~Ǐ9˗Ǐ?~Ǐ?~1|˗o?~Ǐ?~~o |Ǐ?~Ǐ?>/_>~˗Ǐ?~Ǐ?~Q}> <0… :|1ĉ+Z1ƍ;z,O_|$˗/_?~Ǐ?~?~g|}Ǐ?~Ǐ˗o?˧Ǐ?~Ǐ?~h_|}/_|>~Ǐ?~Gc~Ǐ?~Ǐ?~dO_|}T/_>}>~Ǐ?~GC~Ǐ?~Ǐ?/_>}>N/_}>~Ǐ?~c~? 4xaB,h „ 2l!Ĉ'Rh"ƌ7r/_|:v/_|:vرcǎ;vرcLj˷_ǎ˗o;vرcǎ;vؑa?}ؑ!|رcǎ;vرcǎ˗O_!ӗ/cǎ;vرcǎ1ۗ/>;R/_}870_ǎ;vرcǎ;Z/_>~;j/_>~'0߿}رcǎ;vرcLJׯcǎ˗o|o߾uرcǎ;vر#Cӗ/> H*\Ȱ?|/|:tСC:tСC:tСC˗/?:t!|sX0@}ϡC:tСC:tСC:taAϡC:tH|s(0@_>:tСC:tСC:tСC˗C:tP|so |ϡC:tСC:tСC:t?~ |O@ ۗ/<_|/_>~ H*\ȰÇ#JHŋ3jo_|]0_C~G1_~W߾|۸qƍ7nܸqƍ˗||㧯|O| '0@}/> ̇_|'p "Lp!ÆO@ DPB >QD˗O_?_>o߿~3o?O`>~ G> g`?$XA .dC H*\ȰÇ#JHbA}g!|߿|/߿߿80| '0| o~? 4h|,h „ 2laA$XA .dC%NX |x0| '0}Gp߿| '0| ̇P8_|'p "Lp!Æ˗? 4xaB 6tbD)VDO_|,g0| '_>~o?}'0߿~O`>#o߿~,/~-Zha|,ZhѢE-Zo_|Y0@/߿߿|8_|ӗ/_?'0|o˗(߾|O@ DPB >$/_>!B"D!B"A~bB B`?}"D!>̗/D!B"D!B`?}`| Bq |"D!B/_>!B"D!B"B"D!B} B"D˗"D!B"D!B_|A"D˗oD!B|A"D!B"Dӗ/>!Ba|"D!BD/_>!B" " " h_|'p "Lp!ÅׯaÆ 6lذaCkذaÆ 6lذaÆ 6lذ~װaÆ /_}6lذaÆ 6T/_ 6lذaÆ 6lذaÆ 6/_}6lذaǯaÆ 6lذaÆkذaÆ 6lذaÆ 6lذaÁׯaÆ */_~ 6lذaÆ 6/_ 6lذaÆ 6lذaÆ 6,O_|6lذ}װaÆ 6lذaCkذaÆ 6lذaÆ 6PC 5t@˷,h „ ӗ/߾ .\p… .\x0_| H*\ȰÇ#JHňŇŋ/^t/_/^xŋ/N/_}/./~/^x"|]xŋ/^x}wbAŋ/^/_/^xŋ/^/_|.^O_|.^xŊxŋ/^xŁ˷ʼnŋ/^/_/^xŋ/^4/_>}.>ܗ/~/^xExŋ/^xEBwŋ]tQA <0… :|1ĉ+Z߾|H_|a#Fˇ#F1bĈ#F˗F~#F1b/_>1bĈ#F1bO_|&ۗ/>1bĈ#FÈ#F1bĈ#Ƃ˷~#F1b1bĈ#F1bD/_|˗/_?1bĈc|aĈ#F1bĈ~gp_|aĈ#F˗#F1bĈ#Fۗ/~˷#F1b@'p "Lp!ÆB(q"Ŋ/b/_|e̘1cƌ˗/cƌ3f̘1cƌ ˗_ƌ3f̘Qa|2f̘1cƌ3f̘|e̘1cƌ˗/cƌ3f̘1cƌ ˗_ƌ3f̘Qa|2f̘1cƌ3f̘|e̘1cƌ˗/cƌ3f̘1cƌ ˗_A~ӗ1cƌ3^̗/_ƌ3f̘1cƌ3/? ̗1cƌ3b̗/_ƌ3f̘1cƌ3/?O |/_>3fQF1P> H*\ȰÇ#JHŋ ˗A} O /cƌ3fd/_3f̘1cƌ3f$/_>~'0?/cƌ3ft/_3f̘1cƌ3f$/_>~ O@? 4xaB 6tbĄ(QD%J(QD%J/_>~ O ?(QD%J/_>%J(QD%J(QD0@_|I(QD%J̗/D%J(QD%J(QbC}˗/>}I(QD%J/_|%J(QD%J(QD 'p@$XA .dC%.̗/ĉ'N8qĉ'N8?? 4xaB 6tbD 7qĉ'N8qĉ'N`>'p "Lp!ÆB(a|&N8qĉ'N8qĉ8,h „ 2l!Ĉ˗oĉ'N8qąoĉ' ܗ/_|&N8qĉ'6̗/ĉ'N8qĉ 'p`>~ H*\Ȱa|СC:tСC˗ϡC:tСC:`>O@ DPB ˗OC:tСC:/_>:tСC:tP`| /_|:tСÅsСC:tСCСC:tСCۗ/߾/_|:tB~:tСC:t!|9tСC:tСC˷_>}˗/?:tСC:tСC:/_>:tСC:t|O|8`A&TaC!F81a?$XA .dH0_| 6lذaÆ 6lذa(߿ O@ DPB >QD'p "Lp!CkذaÆ 6lذaÆ  ̗/>} ̗/_> 6lذaÆ 6lذaÁ5lذaÆװaÆ 6lذaÆ 6/_~/_| 6lذaÆ 6lذaC5lذaÆװaÆ 6lذaÆ 6/_|˗/_>~ 6lذaÆ 6lذaC5lذaÆװaÆ 6lذaÆ 6`>O@ DPB >QDQH|QH"E)R`>O@ DPB >QąQH|QH"E)R|H"E)RHQ ?})R(0_|)RH"E)"E)RH"EQH|QH"E)R80?)RH"E G"EG"E)RH|(RH"E)R$OE) ̗/E)RH"ńG"E)RH"A~(RHQ`|(RH"E)&̷a>):ܗ/>(߿| H~ϠA(,h „ 䧏!C 2T/_> 2dȐ!C 2dȐa|SC O`|ǰ`>70 c!C  䧏!C 2T/_> 2dȐ!C 2dȐaB O@ D>~/_>G0A~O_|G_?O |?}#Ϡ}ӗO?}OB OB *TP`|*TPB *TPB *L08_> Hw_>+`}W0߿|/@~'0_|O`>? *T8> *TPBSPB *TPB 0 < ? ? 4xaƒ˗/_>~ W0_| /@} Wp_|_>~ |(߿|/߿o?$XA ӧPB *T(0_| *TPB *TP‚8`A߿|8`A&<~ _> 7p`ۗ߿|7P`>0@߿| o| '0}'p "L> *TPBSPB *TPB 0 <> ? 4xaƒO_>}/_|'|g0@O ?'0_| '0|PB ӧPB *T(0_| *TPB *TP‚O@ 0'p`> H"/_>}ӗ/?g0߿|˗߿|3o |˗?~/? _߿|? 4xa„)TPB  ̗/B *TPB *T|*T`>'p|8`A&TaC!./bĈ1bD1bĈ#F(P_|˗o|"F1bĈ/bĈ1bD1bĈ#F(P_|oa>#F1bĈ#FO_Ĉ#:̗/_Ĉ#F1bD_|"F1bĈ#F#Ft/_#F1bĈ1|"F1bĈ#F#Ft/_#F1bĈ1|"F1bĈ#F#Ft/_#F1bĈҗ/,h „'p "Lp!ÆB(qC~(RHQ`|(RH"EGb|(RH"E)R$OE) ̗/E)RH|(R,E)RH"EH"EH"E)>ԗ/EH"E)RH ?})R(0_|)RH"ŇH`>)RH"E)䧏"E˗"E)RP_|)"E)RH"EQH|QH"E˗"łQH"E)RH>)R/_>)RDE=|8`A&̷ ? 4xaB 6tbD <0… ˗aÆ 6lذaÆ װaC H*\Ȱ|:tСC'p "Lp!CkذaÆ 6lذ!C}5lذaÆ 6lp|5lذaÆ 6lذaÆװaÆ 6lذaCkذaÆ 6lذ@kذaÆ 6lذaÆ ˗aÆ 6lذaÆ װaÆ 6lذaÁװaÆ 6lذaÆ /_Æ 6lذaÆ ˗aÆ 6lذaÆǯaÆ 6lذaÆ 6/_ 6lذaÆ 2ԗ/_Æ 6lذaÆ ˗_Æ 6lذaÆ 6@ <0… :|1@}I(QD% /?%J(QD ˗OD%J(q|$J(QD˗D%J(QD'QD%JP_|%J(QDOD%J(QĂ(QD%J\/_>%J(QD'QD%J(Qb|I(QD%.ԗ/D%J(Q@(QD%J(`|$J(QD˗OD%Jџ>}˗O>}$J(QD%J/_>%J(D-|8`A&TaC!08`A&TaC!F0_|'N8qĉ7qĉ'NT`>O@ DPB >Q|M8qĉ'ԗ/ĉ'N8q> <0… :|1D8qĉ'N/_'N8qB ? 4xaB 6tbD 7qĉ'N8P_|'N8qD(? 4xaB 6tbD 7qĉ'N8P_|'N8qĆoĉ'N8qb|M8qĉ'ԗ/ĉ'N8|M8qĉ'Nt/_'N8qā8qĉ':̗ĉ'N8qD8qĉ'N/_'N8qC~&N8qĉ'>̗/ĉ'N8q@}M8qĉ'N8qĉ'Nd/_'N8qā8qĉ':oĉ'N8q|M8qĉ'ԗ/ĉ'N8!˗/?$XA .dC%6̗/ĉ'N8q@}M8qĉ˗O_?oĉ'N8q|M8qĉ'ԗ/ĉ'N8`?}W_|M8qĉ'ND/_'N8qā8qĉ'/_>~ ˗ĉ'N8qD8qĉ'N/_'N8q@ϡ}7qĉ'N8q`|&N8qĉ˗oĉ'NO_|&/_~'N8qĉ˗oĉ'N8q @}'p "Lp!Æ./_~ӗ/?!B"D˗"D!BB}A"D!ۗ/>ۗ/~!B"D!̗/D!B"ą"D!:/_>~! /_>~!B"D!̗/D!B"ą"D!2/~!/_}!B"D!̗/D!B"ą"D!&/_} B\/_>} B"D!B̗/D!B"ą"D!|O@ Dp |SPB *TPB "̗/B *TPB *T|*TPB *Th߾|SPB˗o? *TPB *TPa|)TPB *TPB ˗OB *TPB˗oB *D/_>}*TPB *TPB˧PB *TPB *,/_> *TPB  /_>~ *TP~PB *TPB */_> *TPB *TPaA}'p "Lp!Æ ۗ/>>|h߾|{Ç>|0_|>|Çԗ/Ç>|P`?}{CC Ç>/_>|Ç ˗Ç>|/_>}>|~a|=|Ç˗Ç>|Â{Çۗ/>>|}a>~/_>>|a|=|Ç>|XP_|>|B~Ç˗/_ ߿|? 4xaB 6d/_>:tСCӗ/C:tp_|9tСC˗oÄ/_:tСCСC:tСsСCӗ/>:tСBϡ|˗o`>:ta|9tСC:t|:tСÄϡC:t(_|9$O|/C:t`|:tСC:tO_|:tСAϡC:th|s/@~0_?$XA .dؐa|:tСC:tO_|:t!~@  o`}`> ,/_>}8`A&TaC˗"D!BB}A"D"so~!|"D!6̗/D!B"ą"D˗o?3o_>~O?~ GP?˗| ܗ_>ۗ/>!B"D"D!BP_|!B_|`>'0|??} /߿}"A~ <0… O@ ̗/,h „ 2l!Ĉ'QD˧D(߿|/߿> ߾~'0߿|  $XA .dp|'p ˗? 4xaB 6tbD(QDO _߿|O |/߿|˧OA $H?~ <0… ԗ/? СC:tСsСC˗o?2ϡCۗ/>:tСC}s0_|:tСC:/_>:tp |sa~9ta?}sСCԗ/? СC:tСsСC ӗ/>:t!B~СC:,/_>˗ϡC:tСCСC/_>}:tСC˧C:t|9LP> H*\ȰÇ# ԗ/D%J$/_|$J(QA'QD%˗Ă(QD%J\/_>%Jh|(QD˗D%J(P_|$̗/D%J(QB}I(QĄOD˗O_?%J(|I,/_>%J(Qą(QD ˗D%*/_}$J(QD'`|$J(QD˗OD%6/_}$J(`?}(QD˗Ă <0… :|1@}I(QDOD˗/?%J(q|I,/_>%J(Qą(QD˗D˗O_?%J(|I,/_>%J(Qą(QDۗ/>%JLo_|I(QDOb|I(QD%.ԗ/D%JX_|I(`|(QD%Ă(QD%J\/_>%J(`?}(Q?~'QD%J/_>~ /,h „ 2l!Ĉ'QD%&/_>}$Jlo_|I(QD ˗Ă(QD%J\/_>%J(!|(1a?}(QD%ԗ/?'QD%JP_|%J(Q~ODOD%JP_|$̗/D%J(QB}I(QD˧DOD%JP_|$̗/D%J(QB}I(QD˗/? ˗o?%J(QbC}X`> H*\ȰÇ# ԗ/D%J(q}'a?}(QD%Bԗ/?'QD%JP_|%J(QDO"A~'QD%J/_>~ ˗OD%J(q|$J(QD˗_DOD%J(Q|I,/_>%J(Qą(QD%*/_}ӗ/>%J(QĂ'`|$J(QD˗OD%Jؐ_|!/_>~%J(QDObA'p "Lp!ÆB(P_|%J(Qć˷ |(QD%JL/_>~ ˗OD%J(q|$J(QD˗O߾|(QD%J\/_>~ OD%J(q|$J(QD˗OD%J(QC}X0_|%J(QD 'QD%J(_|$J(QD˗Ă(QD%J\/_>%J(QD'QD%JP_|$̗/D%J(QB}I(QD% |'p "Lp!ÆBXP_|$̗/D%J(QB}I(QD% /?%J(QD'`|$J(QD˗OD%J(Q|o ?}%J(QDOb|I(QD%.ԗ/D%J(Q@3ϟ|%J(QDOb|I(QD%.ԗ/D%J(Q@3O?~˗?'QD%JL/_>~ ˗OD%J(q|$J(QD˗A}_} H*\ȰÇ|A"D!B\/_>!B"D|'?}A"D!&ԗ/?"D!Bq| B"D_|W0@ ߾|8`A&TaC˗ă"D!BP_|!B"D8?}߿'p "Lp!Æ>ԗ/?"D!Bq| B"DO@(0@_|'p "Lp!Æ>ԗ/?"D!Bq| B"D!'p@ H*\ȰÇ# ԗ/?'QD%JP_|%J(QD8p,h „ 2l!ĈOb|I(QD%.ԗ/D%J(Q?O@ DPB >|I,/_>%J(Qą(QD%J/_|I(QD%6ԗ/?'QD%JP_|%&'QD˗/D%J(QC}X0_|%J(QD 'QA~ ? 4xaB 64/_>~:tСC:$/_>~˗ϡC:tСCaC} (,h „ 2lXP_>:tСCԗ/? СC:tСs萡|/_|:tСC9tСC:t谠|9L/_>:tСCӗ/C ˗/?˷ϡC:tСC:tСC0a|:tСC:tO_|.̗/_>}O@$XA .dC%NX@}/_/^x1|.B̗/_>O@ H*\ȰÇ#JHEw1_|/^xbD}]|/_|`> 4xaB 6tbDO@ DP|)T80_| *TPB *TP‚SPa|#/_|'p "Lp!ÆB(q"}8`A&T/_>~ ̗/B *TPB *T|*T`>#? 4xaB 6tbDGC}80_|)RH"Ň8|O,h „ 2l!Ĉ'&䧏"ŇGq`|(RH"EG"|? 4xaB 6tbDGC}80_|)RH"ŇH| <0… :|1ĉ H|Q/_>)RHC}Q(p| <0… :|1ĉ H|Q/_>)RHC}QH_~)RH"E)䧏"ŇGq`|(RH"EGb|(RH"E)R$OEǏ|QH"E˗"łQH"E)RH>˗ŁH"E)>ԗ/EH"E)RH ?} H|Q/_>)RHC}QX0?)RH"E Ӈp_|)ԗ/?G"E)R||8`A&/a„  ܗ/> 'P| H~ϠA3h_ 4hРA $OA~gРA /_>~ ,/_>$XA .dC˗OĄI0?!W0_|̗o`> ˷`[OD0 H˗_„˗0a„ &L0a„ &LP|&L0a> &Lp?/# ?ӗ/#| _|ϟ>}/@}O?~˷/>/0a„ 7P|O@'p ԗ/?˗? 4xaB 6tbD(1a>%&w_>+`>> +_>'@} W_ /|߿}O` 'QB~O@ O@ /_>~̗/,h „ 2l!Ĉ'Qb|$JLo|'|˗O߿|ӷ|O|+߿~O`_>@~%*?$X ?$X|'p "Lp!ÆB(P_|%&OĄ0O|O`} 7_~|/'P |/߿|__@8`A&o>? 4xp|!Dx0_| H*\ȰÇ# ԗ/D (1a|ӗO?W0_|70|'_| ~#/@}O`߾'0?}'QbB~0@ 8_|$H AǏ A ̗/,h „ 2l!Ĉ'Qb|$JTO_|/_>~#`>˗/_? g0@~˗?~/ O`>~70?}/>}/_>~%*`|K/_>~˗Ă(QD%J\/_>'QD%J(QD!/_BP_|$̗/D%J(QB}I0?%J(QD%O'|I,/_>%J(Qą(1!@'p "Lp!ÆB(qC~(˗ŅGq`|(RH"EGb|(RH"E)R$OEP_|(̗/E)RH|(R,E)RH"E/_>~˗ŁH"E)>ԗ/EH"E)RH ?}ǏB}80_|)RH"ŇH`>)RH"E)䧏|Q\/_>~˗"E)RP_|)"E)RH"EQ/? ˗,hP`|8`A&TaC!F/_>'QD%J(QDI/_>~˗Ă(QD%J\/_>'QD%J(QDI/_>~˗Ă(QD%J\/_>'QD%J(QDI/_>~˗Ă(QD%J\/_>'QD%J(QDI/_>~˗Ă(QD%J\/_>'QD%J(QDI/_>~˗Ă(QD%h! <0!|,h „ 2l!Ĉ'F /? 4O_| 4X0_| H*\ȰÇ# ԗ/D 8`A&TaCСC:, /? 4O_| 4X0_| H*\ȰÇ# ԗ/D%J(Q@(QD˗Ć'`|$J(QD˗OD%J(Q|I(QDObC}X0_|%J(QD 'QD%J(_|$J(Qć'|I,/_>%J(Qą(QD%J/_>~%J(QCP_|$̗/D%J(QB}I(QD% /?%J(|Il/_>~ ˗OD%J(q>'p "Lp!ÆBT/_>~#F1bDѡ|E4/_#F1bĈ1bĈ#F_|"F1bĈ/C}h0_|#F1bĈ˗/bĈ#FQ|E1bĈ ˗_D`|"F1bĈ# ԗ/_Ĉ#F1B1bĈ#//|E1bĈ#F/_#F1bD1bĈ#F$/_>~˗_D1bĈ#F(P_|#FQDEB˗,h „ 2l@P_| ̗/D!B"ą"D!B(_| B"D C}x0_|!B"D˗"D!B?˷ϟ?!B"D|A!B"D "D!B`> O@ DPB :/˗C{Ç>||>|Ç"0'p "Lp!Æ˗Ç!|=|Ç>|XP_|>|Ç'p@$XA .d|A!B"D "D!B|O@ DPB >/_>~˗ă"D!BP_|!B"D'p ,h „ 2l@P_| ̗/D!B"ą"D!B_|"D!*/?|A"D!B\/_>!B"D˗"D!B_| >ԗ/?"D!Bq| B"D! /?!BBP_| ̗/D!B"ą"D!B8P_>!B"CP_| ̗/D!B"ą"D!B8?~ H*\ȰÇC}x0_|!B"D˗"D!B~"D!B_| >ԗ/?"D!Bq| B"D˗/~"D!BD/_>~˗ă"D!BP_|!B"D ˗O_?˷D!B|A|/_>~˗"D!BB}A"D!*/_}˗O_?!B@P_| ̗/DADAB˗? 4xaB 6t"|sO_| B"DC}x0_|!B"D˗"D!B}Q}"D!:/?|A"D!B\/_>!B"ā"B~"D!2/?|A"D!B\/_>!B""~"D!*/?|A"D!B\/_>!BC"D,h „ 2l_|:/_>~˗ϡC:tСCСC:tȰ_|9t_|9tСC˗Ca|9tСC:t|:tСC˗O_?ӗ/>:tСCsp|9L/_>:tСCӗ/C:t~ϡC˧C:t_|:/_>~˗ϡC:tСCСC:tX_|9tP!|sСC9@ <8P_|"$XA .dCOD%J4o_|I(Q`}'QD˗Ć'`|$J(QD˗OD%J$O_|$J_|I(QbDP_|$̗/D%J(QB}I(QD˗D˗/?%J|/_>~˗Ă(QD%J\/_>%J߾|(Q"DOD˗Ć'`|$J(QD˗OD O"~'QD_|'p "Lp!CװaA}k0_| 6lذaÆ 6d/_ 6l/| /~ 6lذ~װaÆ  / ˗_CkذaÆ 6lذ!C}5lذa| 'p_|*/_}6lذaC˷_Æ 6d/_>~ ԗ/ װaÆ 6lذaCkذaÆ/߿}!|kذaÆ ˗/ 6l_|6,/_>~ ˗aÆ 6lذaÆ ˗? 4xaB _[x߾|[p… .4O_|.\pƒpaB}[_|.\p… .\p[p… /߿|-,O_|-\p… */_>}.\pBpaB}[_|.\p… .\p[p… /?}˷p |[p… .\X_|-\p…o„p|-\p… .\p…˷p… _? /_} ,X`~ '0_ o`}` O_|'p "LP|-\P_|./_ .\p… .\|.\p… ˗…70|)̷0};oBo… "/ ˗…˷p… .\p… ӗ/… .\ |[`>˧O_>}O`}'0?}/ '_|߾|-\H_|-\pBpaB}[_|.\p… .\p[p… } <(_ '0|߿} '0?~+ȏ߿~'0|_>/_}"D!B!B!ƒO@ DPB >Q|8`A&T!} @~׏| ̗o`>/~"D!BCA}C`|8`A&TaC!F`> 4xaB  _߿|_(O`?}O`|'p ܗ/~"D!BCA}C`|8`A&TaC!F`> 4xaB ? 4xp`|O`>?~O` ?}_>ӷ|"$o_|!D!B˗B˗B <0… :|1~ H*\Р|O@ ~//_}ӧO`>~`~˧O/>}"O_|"D!B!B!ƒO@ DPB >QDӗ/?-Zh_|Y8_|,&ԗ/?gѢE-ZhѢE˷ϟE-Z/_},Z/_>~˗hE-ZhbA~gѢE˗E˗ńg_|,ZhѢE-Zx|YhѢC~gѢEg1|Y/_>-ZhѢE-&/_>},Zh1!|hѢAP_|,˗/E-ZhѢE/_>~ H*\Ȱ?ϡC/?˗ÄsСC:tСC:t`?}СC/_>~:t|9t8P_|&̗/C:tСC:tСC˧C:l/_|:taBsp|9L/_>:tСC:tСC˗/?:t߾|sСC ϡÁ0a|:tСC:tСC:\o_|9tСÁ˷ϡC9@ <8P_|"$XA .dC%NXbC~wE~wňw|]̗/ŋ/^xŋӗ/'˗O_/N/b|.^xŋ/^߾|x}wŊw|]̗/ŋ/^xŋ)˗/ӗ//^/_>~˗|]xŋ/^xb?}x |xŁw|]̗/ŋ/^xŋ//_>}.^ܗ/}8`A&TaC@}s0_|:tСC:tСC:t/_|:lO_|:tСCϡÁ0a|:tСC:tСC:tP`?}!~СC:$/_>~ԗ/? СC:tСC:tСC˧C˧C:tР|9t8P_|&̗/C:tСC:tСC/_>~ۗ/>:tСC@} /_>$XA .dC%NXņ˷ϟ~#F A}/_>1bĈ#F1b$/_|$˗/_?1b|/_>~˗|aĈ#F1bĈ~p_|aĈcDxP_|.˗#F1bĈ#Fۗ/~˗oF1R/?b|0bĈ#F1bĈq!|#/_|0bĈѢ|a~ˇ#F1bĈ#F ˗o|È#F/?$X|'p "Lp!ÆB(q"Ŋ/b$/_>}2f̘Ѣ|e4/_>~˗1cƌ3f̘1cƌ/cƌ/˗_Fw1_|3f̘1cƌ3fH_|2f̘|e4/_>~˗1cƌ3f̘1cƌ/cƌ/˗_Fw1_|3f̘1cƌ3fH_|2f̘|e4/_>~˗1cƌ3f̘1cƌǯ }˘1cƅѠ|]̗/_ƌ3f̘1cƌ3/?/,h „ 2l|=|O_|"̗/Ç>|Ç>|Ç/?O |/_>>|B{|=D/_>|Ç>|Ç>$/_>~'_>߾>|P|=|O_|"̗/Ç>|Ç>|Ç/@~Ç2/˗C{Ç>|Ç>|/>7`>/?$XA .d0|9lȏ?~Ǐ~Ǐ_|ϟC:tСC:tСC:0_?? 4xaB 6L/_>~O@8`A$? 4xaB 6tbD)Vx>? /_>~˗,h „ 2l_|:O8`8p`?$XA .dC%NXE (,h „ 2l|=l`>'p 'p`>} H*\ȰÇ#JHŋ'p>$XA .d!| 0'p "Lp!ÆB(q"Ŋ/bO@ H*\ȰÇbC  0@8`A&TaC!F8bE1/_|2f̘Ѣ|e,/_|UO@$XA .dC%NT؏?~(RHQb|QH"EǏ|(_|QH"E)R`>O@ DPB ˗oC:tBsp |9L/>:tСC:tP`?? 4xaB 6,/C:t!Cs`}ϡC:tСC:0O@ DPB СC:t_|:$!~:tСC:tС}#/_|:tСC:tСC ϡC:tСC:tСC`>O@ DPB >QD ǯbŊ+VXbŊ ˗O@˗o@~,h „ 2l!Ĉ'& /?8`A&Tp?$XA .dC%/_}`>8`A&TaC!F8a>} H`A3/@},h „ &? 4xaB 6tbD80߿'p "Lp!ÆB(q"B~(˗A(RP?)RH"ņ/߾˗"E)RHD~(˗A(RP?)RH"ņO |G"E)RHq"?}Ϡ|)R|E)RH} 8P,h „ 2l!Ĉ'*䧏`~)/?QH>~)RH"E'p`>} H*\ȰÇ#J> ̧_| G"ŇQH"E)BO_|QH"E)R(>O|/?O@ H0A#/_|$H| <0… :|1DM8qĉ'N萟>/߿}G_| W0| |&wP'N8qĉ8qĉ'N8!?}_#/_>~+Ϡ} ܗ_O_>} | /_?/?GP'N8qĉ8qĉ'N8!?} /߿|/?g0_>O`'_>'0|_߿O@ DPB >Q"|&N8qĉ'NtO|O߾/?O@_߿|_>O_~ 7|7П| ,h „ 2l!Ĉ7q}1_87qć7_׏|`>o`>?'p~_80| <0… :|1DM1?!g_} ̇0| `'>o?3/_| O߾Է|o`| / O>>~'N8qĉ7q"}_|˧`>˧O_>}߿|O`/_>O | /|?}81"?}˗A 'P ϟ|?}?˗o?_|?}O`O@ DPB >Q"|&N | W_ '0|߿}O` WO`>|}'F ? ,/_>~ /,h „ &Ǐ!C 2dȐ!C 2\C 7P_|O`O`>_O` g0߿}'0߿|O cȐ!Ä8`A'p| H*\P? 2dȐ!C 2dpa> 2dhP_?8߿| 0@/߿_߿|7P? /~'0߿|O@? 4xaB8`A'p| H*\P? 2dȐ!C 2dpa> 2dh_>~˧@~#/@}O`߾'0?}W}/|>~70C  ? 4( <0… cȐ!C 2dȐ!C ǐ!C˗O?}O`>~O߿|/|˷O| ϟ|O |/߿}O_|˗/_? 2 2dp>~ 2dȐ!C 2dȐ|2dC 1C 1C 1C <(_>"D!BO@ DPB >Q"|&N8qĉ'NtOąM8Q>~'N8qĉ7qĉ'N8qC~&.oĉ8qĉ'N0'N8qĉ7q|'Nĉ'N8qDM8qĉ'N萟 8qD}&N8qĉ'"oĉ'N8qDM\/ĉ%7qĉ'N8a>'N8qĉ':oB&N(Q'N8qĉ8qĉ'N8!?}7qD'p "Lp!ÆB(a>'N8qĉ':oB&N(Q'N8qĉ8qĉ'N8!?}7qDM8qĉ'NDĉ'N8qĉ雸_'Joĉ'N8q"|8`A&TaC!F8ѡ>} HO@ DP„'p "Lp!ÆB(!@},h „d 2l!Ĉ'F <(@},h „ . <0… :|1ĉ+Z1ƍ;z2ȑ$K<2ʕ,[| 3̙4kڼ3Ν<{ 4СD=4ҥL:} 5ԩTZ5֭\z:2 ;;PK!"5PKؐj?OEBPS/img/oiddg007.gifhGIF87a`?**?***UU?UUU????**?*******?*******U*U?*U*U*U**?*****?*****?*****?***UU?UUUU*U*?U*U*U*UUUU?UUUUUUUU?UUUUU?UUUUU?UUUUU?UUU?**?***UU?UUU?????**?***UU?UUU?????**?***UU?UUU?ժժ?ժժժ???**?***UU?UUU?????***UUU,` H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIM͛7o޼yc>(w͛7o޼1|˗?~y͛7o䘏`㷏_>g0͛7o޼y&|ӷϟ|`7o޼yMo_>~ _>? 4xaB 6tbD)VxcF9v80?70>~`?~Ǐ?~@|/_>~Ǐ?~Ǐ?~Ǐ?~Ǐ?~Ǐ?~Ǐ?~(@~,ȯ,h „ 2l!Ĉ'Rh"ƌ7r!?$XP ?$XA .dC%NXE5nѠ~y`>  <0… :|1ĉ+Z1ƍ;0@8`AO@'p "Lp!ÆB(q"Ŋ/b̨q#ǎ'p`> H'p 8`A&TaC!F8bE1fԸcG (p,h?~ H@$XA .dC%NXE5nq`? <|,8? 4xaB 6tbD)VxcF9v`>'p 0 O@ DPB >QD-^ĘQFO@8`AO@'p " <0… :|1ĉ+Z1ƍ'p`>~ H'p "L,h „ 2l!Ĉ'Rh"ƌ7^08`AO@ DP?$XA .dC%NXE5n̸O_>}80 O@ 4/_> H*\ȰÇ#JHŋ3jܸǂ8` H? 4xaB 6tbD)VxcF1˗/_>}8 0 O@ 4/_> H*\ȰÇ#JHŋ3jx|  <`>   H*\ȰÇ#JHŋ3j0_|O$H,X@}  

׏@}'p`?} ߿8 ~ H? 4xaB 6tbD)VxcF˗/_> 8߿ǯ`> OAO@ D/_> H*\ȰÇ#JHŋ3j_|0'p 8@~+X>$XA <0… :|1ĉ+Z1ƍ˗o@? 0 O_'p "/?$XA .dC%NXE5nt/_|'p@ H?} H 'p A8`A˗,h „ 2l!Ĉ'Rh"ƌ7:/_|'p@ HP @,h B$XA <0… :|1ĉ+Z1ƍ˗@? O@ <? 4x |'p "Lp!ÆB(q"Ŋ/b̨qC}'`>ӧO@~? ۗ/@~̗? O@ 4/_> H*\ȰÇ#JHŋ3j_| O@ O@W| ,X`? 4xaB 6tbD)VxcF˗/_>8`8@~$/_ ,X`A~O@ DPB >QD-^ĘQF˷>$X>$(_>} W` ,X_|8`A&TaC!F8bE1fԸ|`> $? O_A,X` /?$XA .dC%NXE5n`>7p @}'P ?$(_>} W` ,X_|8`A&TaC!F8bE1fԸ1> ?|˧ A} ,X` ˗,h „ 2l!Ĉ'Rh"ƌ7F0 ?8@~$/_ ,X`A~O@ DPB >QD-^ĘQF8`~#? O_A,X` /?$XA .dC%NXE5n`> ?8@~$/_ ,X`A~O@ DPB >QD-^ĘQƊO ?$(_>} W` ,X_|8`A&TaC!F8bE1fԸc|˗/_>~ ۗP_>#G9rȑ#G9rT/?˗C~%̗cD~ȑ#G9rȑ#GO|ǐ_>~ _|8rȑ#G9rȑ#GS/_|1o_|8F/?9rȑ#G9rQa|˗/_>~ ӗ0_>#G9rȑ#G9rT/?˗C~%̗cD~ȑ#G9rȑ#G(_>$_|+XP | ̗` ,X |'p "Lp!ÆB(q"Ŋ/b̨q#F}˗/_>~ ӗ0_>#G9rȑ#G9rT؏BǏ|˗cD~ȑ#G9rȑ#G 0O|7p8P`|8`A&/?$XA .dC%NXE5nO|?˗ooO@ D_|8`A&TaC!F8bE1fԸ1"?+؏}9̗A}q/_>9rȑ#G9rȑ~̗`|,O@8`A&/_> H*\ȰÇ#JHŋ3j_>? 4xa <0… :|1ĉ+Z1ƍ;z/_>?~Ǐ?~ǍǏ?~Ǐ?~/_>?~Ǐ?~ǍǏ?~Ǐ?~/_>?~Ǐ?~ǍǏ?~Ǐ?~/_>?~Ǐ?~ǍǏ?~Ǐ?~/_>?~Ǐ?~ǍǏ?~Ǐ?~/_>?~Ǐ?~Ǎ? 4xaB 6tbD)VxcF9v_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~?~ǏǏ?~Ǐ?~_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~Ǐ?~Ǐ,h „ 2l!Ĉ'Rh"ƌ7rq#|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~q#|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~q#|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~q#|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~q#|}Ǐ?~Ǐ7˗Ǐ?~Ǐ?~4`"|}Ǐ?~G߿'p OA 4hРA~O@ DPB >QD-^ĘQFϟ|/?ȏ|3˗_ǎ;vرcǎ;v80|o| `cǎ;vرcǎ;v`@~_njױcǎ;vرcǎ;G0~O@'P} H*/_> H*\ȰÇ#JHŋ3jq`>~o`>}/~:r/;vرcǎ;vq?}_|ӗ/?˗/_cǎ;vرcǎ;vؑ#|uرcǎ;vرcǎ;r/;vرcǎ;vر#A~ H@ H? 4xaB 6tbD)VxcF9v$`> ? 4x |'p "Lp!ÆB(q"Ŋ/b̨qc}q ?$Xp ,hA~O@ DPB >QD-^ĘQƋ8P,h@~ H@$XA <0… :|1ĉ+Z1ƍ'p`>~ H'p 8`A ˗,h „ 2l!Ĉ'Rh"ƌ7Z0'p 0 O@ 4/_> H*\ȰÇ#JHŋ3jh|O@ `>    ,/_>/_> H*\ȰÇ#JHŋ3jܨ? O@'p  ˗A~O@ DPB >QD-^ĘQƌ׏@~ H@$X`A~#/_> H*\ȰÇ#JHŋ3jx| <|,8? 4X_|˗,h „ 2l!Ĉ'Rh"ƌ7^O'p  O@'p  ˗A~O@ DPB >QD-^ĘQF8`} ؏}8?$Xp ,h |/?$XA .dC%NXE5ntȏA} Hp ? O@O@ /? <0… :|1ĉ+Z1ƍ ˗ |,hp ,> ? 4h_|˗,h „ 2l!Ĉ'Rh"ƌ76̗/_>~8p>  O@8`A˗A~O@ DPB >QD-^ĘQƆ˷ |OAO~ ߿  ? 4xaB 6tbD)VxcF˗/_> 8߿?OG A8`A |'p "Lp!ÆB(q"Ŋ/b̨qc~o |߿'p@~8`>~+X>$XA~#/_> H*\Ç#JHŋ3j0_| O8?8 A~+X>$XA~#/_> H*\ȰÇ#JHŋ3jP_| O8?$X04(P,h |/?$XA .dC%NXE5nt/_|'p@ HP @, <0@~#/_> H*\ȰÇ#JHŋ3j_|0'p A H'p  ˗A~O@ DPB >QD-^ĘQƇO |П> O@8 ?$X`A~#/_> H*\ȰÇ#JHŋ3jp_| O@ O@W| ,X`AG_|8`A&TaC!F8bE1fԸ!|0 ˧ A} ,X` |'p "Lp!ÆB(q"Ŋ/b̨qC>$X>$(_>} W` /_>? 4xaB 6tbD)VxcF!'P?8p`>} HP | ԗ` ,(_|˗,h „ 2l!Ĉ'Rh~0 Ǐ? H*\ȰC˗o?~ H@~ HP | ԗ` ,(_|˗,h „ 2l!Ĉ'Rh?} O@~o}'P}'p "Lp!Æ(P?$8_|O@W| ,X`AG_|8`A&TaC!F8bE˗/>~Y}˧?-Zl`>'p~/_|8@~$/_ ,XP |/?$XA .dC%NXa}ϟņ˗/>-Zp|,?'p A+HP_ ,X@~#/_> H*\ȰÇ#JHbC~b~ϢEO@ ?$(_>} W` /_>篠|WP`  <0… :|1ĉ˷E ˗E)J0A~ HP | ԗ` ,(_|˗_A ԗ|,? 4xaB 6tbD˗E˧"E'˗o@~|˧ A} ,X` |O@}O`>} _|8`A&TaC!F8|(R/_~)R(1_> ˗/?K/ňG_|?~O`>?}O ?)RH"EG"H"ňS/_|1䗏_|(F/?w0߿}/| '0߿|˗@~)RH"E!׏"EG"E_|c/Q/_>`_>O`08`A&TaC!F8`|(RXP_>)R/?˗C~%̗bD~#/_>㧏߿|O`>?~O ?)RH"EG"EH"ŇS/_|1O_|(F/?w0?/>} _'0?}H"E)RP>)E):̗ϟBǏ!|G1"|/? QH"E)Rh0>)E)r }8?ǯ`A+H0_ ,X@~#/_> ,X`>$XA .dC(,h „ ˷p… ϟ .\p‚-/_|/B-\ |/ .\p… .\p!| .\`|.\pB}p… .\ ? ?˗/_? ˗ A$H A /_> }#H A ? 4xaB 6t`O"D"ćD!B<0 'p`| 8p| _>} H˗A~;O}&L80_„ &L0a„ &L80A~Ǐ߿|K0a„/a„ &@}/_>O} /?/˗ϟ@}/_> H*\ȰC˧/?o_>|?}=|a|ϟ>|_}+/A <|/ >'0'?~/|o|} O@ DPB 'p|(߿|? 4xa|˗_„ &Lo_>}ϟ &L0a„W0_%LX| 

_>~7߿|70|/| H*\0a>} 80A}O_O@ D0?ۗ0a„ ӗ/>ϟ &L0a„ &L? 'p "/_>`> '0| `>O|70|/? 4xaB "/a>O ?}kذ| ˗O /_|80_? H*\ȰÇ#J$/_> }ӷ| '0|ϟ}'0?}'0|Sĉ'*oĉCO_|_}?'? 4xaB 6tbD |!/߾O`>?}O_|/?'0|Oa>'N'>oa}˧_? O_|П'? 4xaB 6tbD |M81b>'N>7bs>} O@~'p`?~ۧ`>П '? 4xaB 6tbD |M81b>'N o"| 7џ?~O@Ǐ_?П O ,h 2l!Ĉ ˗A~8qb|&N8Q!?} O|ӷ/?'_|˗?}o_|ۗ?W0 (? O@'? 4xaB 6tbD |'p "Lp!|8`A&T!B~3o?/|/@~/|>/aÆ 8`A O@ DPB >Q"A~#`> 4xaB O@ DPBK`O`>'߿| '0_}װaC H|'p "Lp!ÆB( |0 <0… 'p "Lp!C%Gp߿|'0|O@80|O`>7P`> HO@'? 4xaB 6tbD珠?$XA .\,h „ 2DO_B~O߾'0|O ? '0|O`>`> 6dП O ,h „ 2l!Ĉ ˗ĉ'oĉӧ_|ӗ/_O`?}߿|O`>˗/_M? @$XA .dC%/'N4ĉ'*oĉ8!@,/_? H*\ȰÇ#J$/_>'Nh0?˗/ ̗/_>} 'P?$80_| +8>$XA .4C O@'? 4xaB 6tbDoĉ 0|/߾W0|)̇'>O|/!@,/_? H*\ȰÇ#J$/_>'Nh0?O| G0_|O | ̷/>˗ϟ}COĉ1_>/!@,/_? H*\ȰÇ#J$/_} H*\Ȑ`> H0| >~ 䧏|/?߿}O  A~8`A&T`> H} o߿|/_?'0}П O ,h „ 2l!Ĉ O@ DPB'p |'p ̗/_>}'P߿߿ ?O@ DPB8`̗_>~/?~_󗏟@$X_~8`A&TaC!FH|,h „ 2D? #o?}(߿| /_>'0߿~'0|8_O@8`A&T?$X_|o`?~˗O?'0_> H|'p "Lp!ÆB( @,h „ 2<G0}7P||o߿| O߾$O@,h „ ? /?o`}˗`˗O@$X_~8`A&TaC!F8bES/_|˗}/B /߿O/?}/>} (>$XA .4C/_/?}_ O @,/_? H*\ȰÇ#JHE]x1"?}/^_DO`ϟ| ϟ| O@'? 4xaB 6tbD)V0/Fŋx @,/_? H*\ȰÇ#JHE]x1"?}/^ŋ8`A O@ DPB >QD-"b~1ł]xq`>/O@'? 4xaB 6tbD)V0?{ax|˗E H|'p "Lp!ÆB( @,h „ 2<,X0|˷O>} ?~/_~߿}o_>~ ? 4xaB W` ,? @$XA .dC%0 <0… O@ o?_~_>~ϟ>o߾ _> O@ DPB8|/_/_>~/| ܗ/П '? 4xaB 6tbD'p "Lp!C8`AO`_ G_>70|4X|,h „ "'0_ o_>_߾|/@,/_? H*\ȰÇ#J$/_} H*\Ȑ`> H A /߿߿|@O`> '0|8P ?} H*\h0?$80_>_>}o`'0_8`A O@ DPB >Q"A~8qDIo>~o߿|/߿| / '0}O`M8a> o`>ӗ/_>} 70߿|˧_>$X_~8`A&TaC!FH_|&N8`>O߿|O_}O_|˗O>~ϟ| '0_D~&N0 70|߿| O?П O ,h „ 2l!Ĉ ˗ĉ'o|M'>a| 'P_~'0|/_>~П '? 4xaB 6tbDoĉ 7`&N|Oĉ7qbC$X_~8`A&TaC!FH_|&N8`>'N'>oĆ H|'p "Lp!ÆB( | <0… O@ DPBkذaÆkذ!C$X_~8`A&TaÄsX?~:,/_>'p "Lp!C H*\!?} 6l`> ˗| kП O ,h „ 2l0| ϟ>/?8`A&T?$XA .d 6lx0?_C'p  <0… &G0?_|O ?~9t |/?$XA .D,h „ 2DO_Æ 6<ϟ|'P|ۗ/?O_|˷o`~/>$/_? H*\Ȱa|} '0?9t |/?:tH0?:tP ?}:tP`> /|/?_~㗏߿}ׯ_~O@ <0… &G0?} O ? ۧϡC |9tСC9tСCsСCS/|O`>}˗O?70|ۗ? O ,h „ 2l0|`>߿,h „G_|&L0a„ 0a„ &L ?} &L0a„%/|O`>}ӗ/_|O`П'? 4xaB 6L@~O?G?9tp |/?:tH0?:tP ?}:tP`> /_?@}/>} /_?$(0_? H*\ȰaB|/_>~ԗ/?/?СC СC ϡC Oa|O`>?}/}'0@'p O@ DPB >Q"A~#/_>'Nĉ'*oĉ8|8|'p "Lp!ÆB( |/'Foĉ7qćM0_>$H0_? H*\ȰÇ 'p 'p  ˗A~;x} H*\h0_? 2? O ,h „ 2lB~ H@~ HG_| 4xaB * <0…cȐ!Á H`|'p "Lp!ÆϡC8` HG_|8`A&TaC!F8błYx? ܗo ,h „ 2l(p|O@ `>  ,/_>? 4xaB 6tbD)V,/? 'p A <0… 0'p 0 O@ /? <0… :|1+ܗE8 A} O@ DPB 'p@} H'p 8`A |'p "Lp!ÆB(q"Ŋg"A$(|'p "Lp!Æ'p@$X8` HG_|8`A&TaC!F8bEgѢ@$o_|'p "Lp!Æ'p@$X8`A&߿  <0… :|1ĉ+&/>-'p@~#? 4xaB 6`>O@ `> 4xaB@ H*\ȰÇ#JHB}g"@ۗ/~'p "Lp!Æ'p`~ H'p 8`A?~O@ DPB >QD˗/߾~#?}П@ H*\ȰA} ? 4xP ?$Xp ,hA~O@ DPB >QDӗ/_}Yd߾|П8`A&TaÄϡÁ8` H? 4xaB 6tbD)V؏> ǯ?$X?ӗ/_|'p@$XA .dؐ~:$`>  ԧO@~ܧO>Է@O@ DPB O} H'p 8`A ˗,h „ 2l!Ĉ'Rh_~o>}'p A}۷_?$ <0… :`>O@ 0 O@ 4/_> H*\ȰÇ#JHł HA$? 4xaB 6tX|? A'p 8`A ˗,h „ 2l!Ĉ'Rh"ƌ7Z0_}'p 8`A8`A ˗,h „ 2l!Ĉ'Rh"ƌ76/߾ H8`A~ H@ H? 4xaB 6tbD)VxcF˗/_? HA8` H,h  <0… :|1ĉ+Z1ƍ ˗oAoAO@'p@$XA? 4xaB 6tbD)VxcF˗/_> 8? ?O@P O@ D/_> H*\ȰÇ#JH|Y/_>},Zh"~G`>_}'p@~8 $HP>$XA <0… :|1ĉ+.G0 ϢE-̗/_~8p?$(>$8߿ $? 4x!|'p "Lp!ÆB(q"Ŋ ϟ|/?3~߾| '0@}hѢł˷o |'p ϠA8`A˗,h „ 2l!Ĉ'R0|o| `>۷} '0_Yh"A~7`>O@O@ ?  <_|8`A&TaC!F8bŅo? '0|˗_>O`>hѢE˗ϟ@? O@ <? 4x |'p "Lp!ÆB(q"Ŋ '߾|(߿| (P_?'0| '0| H*\Ȱ|'`>O@8`AO@ 4/_> H*\ȰÇ#JH|| _>O__>'0YhbA}'`>'p ~'p AO'p A H? 4xaB 6tbD)V\O_|/_~O` ӗ/>~O_|˧O|ϢE˗/_> H`A HP | ԗ` ,X |'p "Lp!ÆB(q"Ŋh0_A~/^/_|O@ O@W| ,X`? 4xaB 6tbD)VȰE x||,HP/+X` ,/_> H*\ȰÇ#JHŋ3jq_|`> ? O_A,X` /?$XA .dC%NXѠ|Cob>,*gѢŊ(߿} HP |O@W| ,X`? 4xaB 6tbD)V4?g1E,ZhQ|O@_|O@W| ,X`? 4xaB 6tbD)V4o`~ '0߾|ӗ/'P?~ۗo@~'P߾|/E-0 ?8@~$/_ ,X`A~O@ DPB >QD | ߾}㷏߾ _>۷_>7П>/߿}gѢE8`A#? O_A,X` /?$XA .dC%NX`?~O`>ӷϟ| '0|'|O`hѢŁ8@#? O_A,X` /?$XA .dC%NX?O`>o_>~ O` _맏|/߿| <0…  `>?8@~$/_ ,X`A~O@ DPB >QD 7_'0O>O`>O ?| O߾Yh|)/_|˷/|-/?-ZhѢE#˗/>'P_|˗/_?'0|˷?} |/|˧OE-̗ϟBǏ!|g?~hѢE-ZhѢE-Zh`|˗/_>~ 0_>˗ϟE-Z",",", ˗/? ˧ 'p "L/_> H*\ȰÇ#JHŋ3j܈1_> ˗/?K/LjǑ#G9r0_僘b|ȑ#|)/_|˧/a|#˗G9rȑB~=0|C#G[/_|1O_|8F/?9rȑ#DžO_}˷O`˗?~/˗ϟ@}+o?}|˗G˷_|c/_>_|8rȑ#G)|/_>~߾_o߾߿| o|O`  <0… >!/_|˗|6lh_|6lذaÆ 6lذaÆ 6_?} /|/@O`| '0_|O`>5lذaÆ'p A80_| 8p|/>$XA ? 4xaB 6tbD)V0@__߿~_/߿@>~ >~'p "Lp!C'p }8_|8P`|/>$XA ? 4xaB 6tbD)V/@}߾_'0_>O`>}'0| _>_>h} W>s/>/?$XA ? 4xaB 6tbD)V~ӗo|_׏_|߿|O`> ˗/?ӧ߿|˧O?-FO_| "?$? 4xa <0… :|1ĉ+*W0E-ZϢ@~ 8,h „? 4xaB 6tbD)VT`>-ZhѢE- /?-ZhѢE-ZhѢE-Zh!|YhѢE-ZhѢE-ZhѢEϢE-ZhѢE-ZhѢE-ZD/_>-ZhѢE-ZhѢE-Zh"B~hѢE-ZhѢE-Zh"|,Z/_>-ZhѢE-ZhѢE-ZD/EϢE-ZhѢE-ZhѢE-ZD/_>-ZhѢE-ZhѢE-Zh"/?$XA .dC%NXE5nF~Ǐ?~Ǐ?n/?~Ǐ?~F~Ǐ?~Ǐ?n/?~Ǐ?~x1_˗Ǐ?~Ǐ?~/ǏǏ?~Ǐ?~_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~Ǐ?~ǏǏ?~Ǐ?~_|>~Ǐ?~Ǐ6_|8`A&TaC!F8bE1fԸ#|:v4/_>;vرcǎ;vر#|:v4/_>;vرcǎ;vرcǎcǎ;vرcǎ;vؑ#|uرcǎ;vرcǎ;r/;vرcǎ;vرcGױcǎ;vرcǎ;vȑ_|:vرcǎ;vرcǎ9˗_ǎ;vرcǎ;vر#G~رcǎ;vرcǎ;v/_>;vرcǎ;vرcǎcǎ;ꨣ:ꨣ:H _>$X`~4hРA /?$XA .dC%NXE5n(0|E~رcǎ;vرcǎ#?}/_>G0?~u/_>;vرcǎ;vر|} '0/_Njױcǎ;vرcǎ; G0?} O ? O߿|/˗_ǎ;vرcǎ;v(0|`>? 4xaƒ <0… :|1ĉ+Z1ƍ'_O ?'_|/˗_ǎ;vرcǎ;v(П|/_|˗| 䗯E~رcǎ;vرcǎ;v/_>;vرcǎ;vرcǂ H?$XA <0… :|1ĉ+Z1ƍ;0   H*\ȰÇ#JHŋ3jx|O@ `>  QD-^ĘQF8p ,h?~ H@$XA <0… :|1+Z1ƍ'p@$X8` H? 4xaB 6tbD)VxcF/'p} H'p 8`A ˗,h „ 2l!Ĉ'Rh"ƌ7^08`AO@ DP?$XA .dC%NXE5n/_|q`> 4xaB8`A&TaC!F8bE1fԸQ? O@'p " <0… :|1ĉ+Z1ƍ˧ǁ8` H*\ȰÇ#JHŋ3jȱ#A ,h?~ H@$XA .dC%NXE5nؑ | 4`>  <0… :|1ĉ+Z1ƍ;0@oO@'p "Lp!ÆB(q"Ŋ/b̨q#G+`> o_|8`A~ H@~ H*\ȰÇ#JHŋ3j|O@ O@Ǐ@}ǯ,h „ 2l!Ĉ'Rh"ƌ7rĘ/_|'p} ? ,`>'p "Lp!B(q"Ŋ/b̨q#Ǎ˧ |oAO~ ߿ H?$XA .dC%NXE5n䘑_|Oo~ >?} ? 4xaB 6tbD)VxcF9f/_|'p@`>  O@ DPB >QD-^ĘQF˗@? `>  O@ DPB >QD-^ĘQF˗O@? O@OA'p "Lp!ÆB(q"Ŋ/b̨q#G˗o |'p H*\ȰÇ#JHŋ3jȱ#DO |'p  <0… :|1ĉ+Z1ƍ3˗/> 8@@}0 'p A~ H*\ȰÇ#JHŋ3j1|0 ˧ A}8`A&TaC!F8bE1fԸcǃ˗O |,X/O@ DPB >QD-^ĘQF˗/8` HP | ԗ? 4xaB 6tbD)VxcF9vD0@ 8p'p A+HP_>$XA .dC%NXE5na||,8/O@ DPB >QD-^ĘQF'P~ Hp`|˧ A}8`A&TaC!F8bE1fԸcDŽ8 A} ?$(_>}  <0… :|1ĉ+Z1ƍ;*0 A~ HP | ԗ? 4xaB 6tbD)VxcF9v\`> ?8@~$/,h „ 2l!Ĉ'Rh"ƌ7rؐ|?'p A+HP_>$XA .dC%NXE5nb|(߿˗/_>~ HP | ԗ? 4xaB 6tbD)VxcF9v/?˗C~%ԗϣG=zѣG=z/_> ˗/?K/G=zѣG=z_|˗/_>~ ۗ0_>=zѣG=z|)/_|˧/a|=zѣG=zѣS/_|1O_|̗/_/˧? 4xaB 6tbD)VxcF9vLO?П@'P| 8p| o_>~ H*\ȰÇ#JHŋ3jȱ#~̗`|,˗>? 4xaB 6tbD)VxcF9vD/ԗ?$? 4xaB 6tbD)VxcF9vX?'p "Lp!ÆB(q"Ŋ/b̨q#ǎ? )r$ɒ&OLRd@;;PKĊhhPKؐj?OEBPS/img/ditattrs.gifT GIF89a,H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXj% ֯`ÊصױhӪ]kىo]6ܻ#=X6@ׁ╫o35WY&{bɘ.[0v37-Lěwv饜g~6uco M{M[SC׺yyI;|:Sϋ[?vRT{*}P7DO0zGo4>\kf=g}=rf`nc;MH!Lgk#n9Y"K*ך`݁Y `bL:h҉hk6Y>c"= Gx eKR~Qa)fHfiYInFgsƙ?9`򙗄*(qF%z u4)d^ [rni^jf&i:_L**맷Bg溨vZ՜"l1jߑIҶQJwu^[H"b‰fR;:  oYY"#0 ;#A^ laEx^e1YF̥̥ y1ƋΆvx%ל0rCe8 n24W3ԧI5fZ/FMmάxAUlon{ dZwc],6RE=u8S_[B4,+c k<,1K8AݬgA{JSQK^a/Q;-ķd-pe2ಶ/AqI\t ֽJv籈T[r:/f[Xwtl.Uiw$pBq,M'7Yj8;FԪE-_-"p{U@qJ#b? [tӂ`3t-v@~0%H'Q/[U>lR9d5,U.]ҬHe΋;F;Lzd*ƨ"լdycc"^lKhԼ4*s C#:en2PIˈ4QklVE wҞ3V3AϷӘ&˹R-W j J*mQޚe[l1+]l?Zu͎j[=;mՖinLNinjnukv[N*o}_!˖78Sׂ !qKgŅq/ 9%aQrז-'s\5b sg 'so'A?.w%{{E_t_c \dzk~W%R};2z0${ucƲUzs1ǮIJ'}:b}zӂΪi ⢏'9g0 Aw{wxwdD~{ Fp(Ejf w9|s_*P|SsswWB}z~~Ly/?ӏޫMNX~%8Xx;PKkcȌY T PKؐj?OEBPS/img/oiddg009.gif GIF89a999rrr___///ooo@@@OOO𠠠 >>>```<<SA猎 jHɨ$[-l=HV"B$L#~KȶdhU7IFIt^?sHA13g9+!Ao}9D $>f1QI!@NtXB˔uN(1R+dN  S5f,~( DX4n:Ge?ӗ:tb|ah5d3г:4iY4\ݟHR k}v>oڼ^s0} IDS8a5{ԧNh¶# ~LSHFD,H>7]c9ͰC3@VuM҉صw$`G8+hBI{9%<IZSp#LEL Oh%ˆg~Hd'O\BҔxS&P KL`@(+JaS(YChZ| )-%qieBd\e#'M`e֎L0~Wu$~Q,щAr{Wmf%c8H hO^gWy1wY nlLԡA&e 9{`D*'$!q[$ Y3Et}; TvMY5?x M^F6ׄZRLtW]b A 6ОWGjIHr} ̾+u+M<;ԏaəlp{ Zð!Nr=$]!̎X3* p0m|65'lJQ03ܣz{H / .M zzcEx1.X4=GH}[{PyAx24}<xl'~ |A:?J2c{~c"{}'.ukd`we qw3C:G4X ~wAdւ'r{0Ks Jb0z (G%ND=3#$~Eh.UB8~"?8ɢ7נ9MPR5 |AuPaB+4izD7w*w PhH0P$g5BGҠx1I2b>z:sA8% ^U'9X1['? !c,QtIh  3i'g1Hr*;iE|7@pi0$X#zrAz14߸}H( iMqLR@l$4 lj׆zhXEcj a򐏔ظfF`.Q6_ B@b"hܱL-WȒrc)I; 7w a; 5a#;MqIq>&腇I}X;R9-э3cV"H1pF5淊Pɑ12r57jz'](B}lh@x sJ3:gH`I2(4k!jEj*{A i=B!N䈘R$c4f1xn5r?'!3i9_Iq *Ew9 CQ3q33c) nȆpe 8ѐ Ѝh-(QI~!7QR>6Z N)ڄ J(j Hk94)F?. g)m&e(yi4;*IF`#AC@MŃ}NtC +FV:!z`TeDA@)VD,cB|!#O8:I 7c($)QuZvpC"|rz]FPa3jjcC(3qa=?yubP(zo;gar̠+ם&A:a ؘ*@@ 9Pjbʥz~F~=#$JA9#/B pKj*h.:: 4A,s I-{$4!h#(sɥ=ZlʌYW!7`!BmXBj2$:I;B[)2$j&[N_2W #T)@xs9t"u$LѴa9x3:D&W }]AcnM9 z KxIsBaSJAk$h9)a.WGDv3)!"-qsH2=&_`4,w3ɼ[cFD1fRvG9 YK-"SpsײȤflZҢQg; 3;G8(aQ{ArUC1)2vC:8FA@L8X>(1궡Ëb %1yC`[SPA"~#3YV #:"J14s!(Q:?w1ٴ[:c*hRB͙tPk[ {Ȁ7Bf(`V4RھEnTe^J=].-Y,> Β?  2 vS봆 B!3GDlA aSdNRt1a3)28CE-!!TA30(- 1 a -&O>FF!4fArDu2@[bSkC\5VoGBC4 n%$Oe0FuSJ6#D HvE?"!q 3| cuBC@2mڋs J4E#K'M 9>Hl, LD{?RL4 S_$NIJ=+Pqi"b+?0#);@h$#΀b!M>gš2hb0?9@:]ܤ:(4CeTq([v}b94RtB! ]a[t rp+!#%'%(13!4=?ACMOO-QW &XcYGqeqsTuW(z1iKAycm##oəˡ{ُW{=e^#,KJ0? >$!GE1fԸcGA9clAh /aƔ9fM7qԹgO)LUVQG&UiSOFmzR)RfպkעT;PKnPKؐj?OEBPS/capi.htm C API Reference

8 C API Reference

This chapter introduces the Oracle Internet Directory C API and provides examples of how to use it.

The chapter contains these topics:

8.1 About the Oracle Internet Directory C API

The Oracle Internet Directory SDK C API is based on LDAP Version 3 C API and Oracle extensions to support SSL.

You can use the Oracle Internet Directory API 11g Release 1 (11.1.1) in the following modes:

  • SSL—All communication secured by using SSL

  • Non-SSL—Client/server communication not secure

The API uses TCP/IP to connect to a directory server. When it does this, it uses, by default, an unencrypted channel. To use the SSL mode, you must use the Oracle SSL call interface. You determine which mode you are using by the presence or absence of the SSL calls in the API usage. You can easily switch between SSL and non-SSL modes.


See Also:

"Sample C API Usage" for more details on how to use the two modes.

This section contains these topics:

8.1.1 Oracle Internet Directory SDK C API SSL Extensions

Oracle SSL extensions to the LDAP API are based on standard SSL protocol. The SSL extensions provide encryption and decryption of data over the wire and authentication.

There are three modes of authentication:

The type of authentication is indicated by a parameter in the SSL interface call.

8.2 Functions in the C API

This section examines each of the functions and procedures in the C API. It explains their purpose and syntax. It also provides tips for using them.

The section contains the following topics:

8.2.1 The Functions at a Glance

Table 8-2 lists all of the functions and procedures in the C API and briefly explains their purpose.

Table 8-2 Functions and Procedures in the C API

Function or ProcedureDescription
ber_free

Free the memory allocated for a BerElement structure

ldap_abandon_ext
ldap_abandon

Cancel an asynchronous operation

ldap_add_ext
ldap_add_ext_s
ldap_add
ldap_add_s

Add a new entry to the directory

ldap_compare_ext
ldap_compare_ext_s
ldap_compare
ldap_compare_s

Compare entries in the directory

ldap_count_entries

Count the number of entries in a chain of search results

ldap_count_values

Count the string values of an attribute

ldap_count_values_len

Count the binary values of an attribute

ora_ldap_create_clientctx

Create a client context and returns a handle to it.

ora_ldap_create_cred_hdl

Create a credential handle.

ldap_delete_ext
ldap_delete_ext_s
ldap_delete
ldap_delete_s

Delete an entry from the directory

ora_ldap_destroy_clientctx

Destroy the client context.

ora_ldap_free_cred_hdl

Destroy the credential handle.

ldap_dn2ufn

Converts the name into a more user friendly format

ldap_err2string

Get the error message for a specific error code

ldap_explode_dn

Split up a distinguished name into its components

ldap_explode_rdn

ldap_first_attribute

Get the name of the first attribute in an entry

ldap_first_entry

Get the first entry in a chain of search results

ora_ldap_get_cred_props

Retrieve properties associated with credential handle.

ldap_get_dn

Get the distinguished name for an entry

ldap_get_option

Access the current value of various session-wide parameters

ldap_get_values

Get the string values of an attribute

ldap_get_values_len

Get the binary values of an attribute

ldap_init
ldap_open

Open a connection to an LDAP server

ora_ldap_init_SASL

Perform SASL authentication

ldap_memfree

Free memory allocated by an LDAP API function call

ldap_modify_ext
ldap_modify_ext_s
ldap_modify
ldap_modify_s

Modify an entry in the directory

ldap_msgfree

Free the memory allocated for search results or other LDAP operation results

ldap_first_attribute
ldap_next_attribute

Get the name of the next attribute in an entry

ldap_next_entry

Get the next entry in a chain of search results

ldap_perror

(Deprecated)

Prints the message supplied in message.

ldap_rename
ldap_rename_s

Modify the RDN of an entry in the directory

ldap_result2error

(Deprecated)

Return the error code from result message.

ldap_result
ldap_msgfree
ldap_msgtype
ldap_msgid

Check the results of an asynchronous operation

ldap_sasl_bind
ldap_sasl_bind_s

General authentication to an LDAP server

ldap_search_ext
ldap_search_ext_s
ldap_search
ldap_search_s

Search the directory

ldap_search_st

Search the directory with a timeout value

ldap_get_option
ldap_set_option

Set the value of these parameters

ldap_set_rebind_proc 

Set the callback function to be used to get bind credential to a new server when chasing referrals.

ora_ldap_set_clientctx

Add properties to the client context handle.

ora_ldap_set_cred_props

Add properties to credential handle.

ldap_simple_bind
ldap_simple_bind_s
ldap_sasl_bind
ldap_sasl_bind_s

Simple authentication to an LDAP server

ldap_unbind_ext
ldap_unbind
ldap_unbind_s

End an LDAP session

ldap_value_free

Free the memory allocated for the string values of an attribute

ldap_value_free
ldap_value_free_len

Free the memory allocated for the binary values of an attribute


This section lists all the calls available in the LDAP C API found in RFC 1823.


See Also:

The following URL for a more detailed explanation of these calls:
http://www.ietf.org

8.2.2 Initializing an LDAP Session

The calls in this section initialize a session with an LDAP server.

8.2.2.1 ldap_init and ldap_open

ldap_init() initializes a session with an LDAP server, but does not open a connection. The server is not actually contacted until an operation is performed that requires it, allowing various options to be set after initialization. ldap_open() initializes a session and opens a connection. The two fulfill the same purpose and have the same syntax, but the first is preferred.

Syntax

LDAP *ldap_init
(
    const char     *hostname,
    int            portno
)
;

Parameters

Usage Notes

ldap_init() and ldap_open() both return a session handle. This is 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 initialized. If the session cannot be initialized, check the error reporting mechanism for the operating system to see why the call failed.

Note that if you connect to an LDAPv2 server, one of the LDAP bind calls described later SHOULD be completed before other operations can be performed on the session. LDAPv3 does not require that a bind operation be completed before other operations are performed.

The calling program can set various attributes of the session by calling the routines described in the next section.

8.2.3 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 in this section.

8.2.3.1 ldap_get_option and ldap_set_option

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 inherit the options associated with the session that sent the original request that caused the referrals to be returned.

Syntax

int ldap_get_option
(
LDAP            *ld,
int             option,
void            *outvalue
)
;

int ldap_set_option
(
LDAP            *ld,
int             option,
const void      *invalue
)
;
#define LDAP_OPT_ON     ((void *)1)
#define LDAP_OPT_OFF    ((void *)0)

Parameters

Table 8-4 lists and describes the parameters for LDAP session handle options.

Constants

Table 8-5 lists and describes the constants for LDAP session handle options.

Table 8-5 Constants

ConstantType for invalue parameterType for outvalue parameterDescription
LDAP_OPT_API_INFO(0x00)

Not applicable. Option is read only.

LDAPAPIInfo*

Used to retrieve some basic information about the LDAP API implementation at execution time. Applications need to be able to determine information about the particular API implementation they are using both at compile time and during execution. This option is read only and cannot be set.

ORA_LDAP_OPT_RFRL_CACHE
void* (LDAP_OPT_ON
void* (LDAP_OPT_OFF)
int *

This option determines whether referral cache is enabled or not. If this option is set to LDAP_OPT_ON, the cache is enabled; otherwise, the cache is disabled.

ORA_LDAP_OPT_RFRL_CACHE_SZ
int *
int *

This option sets the size of referral cache. The size is maximum size in terms of number of bytes the cache can grow to. It is set to 1MB by default.

LDAP_OPT_DEREF(0x02)
int *
int *

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 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)
int *
int *

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)
int *
int *

A limit on the number of seconds to spend on a search. A value of LDAP_NO_LIMIT (0) means 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 waits locally for search results. The timeout parameter passed to ldap_search_ext_s() or ldap_result()—both of which are described later in this document—can be used to specify both a local and server side time limit. The default value for this option is LDAP_NO_LIMIT.

LDAP_OPT_REFERRALS(0x08)
void *(LDAP_OPT_ON)
void *(LDAP_OPT_OFF)
int *

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 the current setting is read using ldap_get_option(), a zero value means off and any nonzero value means on. By default, this option is turned on.

LDAP_OPT_RESTART(0X09)
void * (LDAP_OPT_ON)
void * (LDAP_OPT_OFF)
int *

Determines whether LDAP input and output operations are automatically restarted if they stop prematurely. It may be set to either LDAP_OPT_ON or LDAP_OPT_OFF. Any non-null pointer value passed to ldap_set_option() enables this option. When the current setting is read using ldap_get_option(), a zero value means off and any nonzero value means on. This option is useful if an input or output operation can be interrupted prematurely—by a timer going off, for example. By default, this option is turned off.

LDAP_OPT_PROTOCOL_VERSION(0x11)
int *
int *

This option indicates the version of the LDAP protocol used when communicating with the primary LDAP server. The option should be either LDAP_VERSION2 (2) or LDAP_VERSION3 (3). If no version is set, the default is LDAP_VERSION2 (2).

LDAP_OPT_SERVER_CONTROLS(0x12)
LDAPControl**
LDAPControl***

A default list of LDAP server controls to be sent with each request.

See Also: "Working With Controls".

LDAP_OPT_CLIENT_CONTROLS(0x13)
LDAPControl**
LDAPControl***

A default list of client controls that affect the LDAP session.

See Also: "Working With Controls".

LDAP_OPT_API_FEATURE_INFO(0x15)

Not applicable. Option is read only.

LDAPAPIFeatureInfo *

Used to retrieve version information about LDAP API extended features at execution time. Applications need to be able to determine information about the particular API implementation they are using both at compile time and during execution. This option is read only. It cannot be set.

LDAP_OPT_HOST_NAME(0x30)
char *
char **

The host name (or list of hosts) for the primary LDAP server. See the definition of the hostname parameter for ldap_init() to determine the syntax.

LDAP_OPT_ERROR_NUMBER(0x31)
int *
int *

The code of the most recent LDAP error during this session.

LDAP_OPT_ERROR_STRING(0x32)
char *

-

The message returned with the most recent LDAP error during this session.

LDAP_OPT_MATCHED_DN(0x33)
char *
char **

The matched DN value returned with the most recent LDAP error during this session.

ORA_LDAP_OPT_CONNECT_TIMEOUT (0xD2)
int *
int *

This option sets the LDAP connection timeout value in seconds. The connection timeout must be set before calling ldap_open. Valid values are 0 – 300 seconds. If the value is set to 0, then the timeout defaults to TCP timeout. If this option is not set, then ldap_open() call times out in 15 sec if the host is not reachable.


Usage Notes

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 error code may be retrieved by calling ldap_get_option() with an option value of LDAP_OPT_ERROR_NUMBER. Note that there is no way to retrieve a more specific error code if a call to ldap_get_option() with an option value of LDAP_OPT_ERROR_NUMBER 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 session handle change permitted is setting the LDAP error code (as returned by the LDAP_OPT_ERROR_NUMBER 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 less than 0x1000 and greater than 0x7FFF that are not defined in this document are reserved and should not be used. The following macro must be defined by C LDAP API implementations to aid extension implementers:

#define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x4000  /* to 0x7FFF inclusive */

8.2.4 Getting Bind Credentials for Chasing Referrals

The functions in this section are used to get the bind credentials of a new server while chasing referrals.

8.2.4.1 ldap_set_rebind_proc

The ldap_set_rebind_proc() function is used to set the callback function that the library uses to get the bind credentials for connecting to a new server while chasing LDAP referrals. The library uses the callback function only if LDAP_OPT_REFERRALS is set using ldap_set_option(). If ldap_set_rebind_proc() is not called, then the library uses an anonymous bind to connect to the new server while chasing LDAP referrals.

Syntax

void ldap_set_rebind_proc
(
LDAP          *ld,
int(*rebindproc) (LDAP   *ld,
                 char  **dnp,
                 char  **passwdp,
                 int    *authmethodp,
                 int     freeit)
)

The reprocbind() function is the function to be called to get the bind credentials of the new server.

When the freeit parameter value is 0, then rebindproc must return bind dn pointer, bind password pointer, and bind authentication method pointer. When the freeit parameter value is 1, then rebindproc must free any memory allocated in the previous call. The LDAP library call this function twice, first to get the bind credentials and second time to free the memory.

8.2.5 Authenticating to the Directory

The functions in this section are used to authenticate an LDAP client to an LDAP directory server.

8.2.5.1 ldap_sasl_bind, ldap_sasl_bind_s, ldap_simple_bind, and ldap_simple_bind_s

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. The routines both take the DN to bind as, the method to use, as a dotted-string representation of an object identifier (OID) identifying the method, and a struct berval holding the credentials. 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.

Syntax

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
);

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

Table 8-7 lists and describes the parameters for authenticating to the directory.

Usage Notes

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 error code if not. If successful, ldap_sasl_bind() places the message id of the request in *msgidp. A subsequent call to ldap_result() 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 subsequent call to ldap_result(), described in, can be used to obtain the result of the bind. In case of error, ldap_simple_bind() returns -1, setting the session error parameters in the LDAP structure appropriately.

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 error code if it was not.

Note that if an LDAPv2 server is contacted, no other operations over the connection can be attempted before a bind call has successfully completed.

Subsequent bind calls can be used to re-authenticate over the same connection, and multistep SASL sequences can be accomplished through a sequence of calls to ldap_sasl_bind() or ldap_sasl_bind_s().


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

8.2.6 SASL Authentication Using Oracle Extensions

This section contains the following topics:

8.2.6.1 ora_ldap_init_SASL

The function ora_ldap_init_SASL() can be used for SASL based authentication. It performs authentication based on the mechanism specified as one of its input arguments.

This function encapsulates the SASL handshake between the client and the directory server for various standard SASL mechanisms thereby reducing the coding effort involved in establishing a SASL-based connection to the directory server.

Syntax

int ora_ldap_init_SASL
(
                OraLdapClientCtx * clientCtx,
                LDAP                    *ld,
                char                    * dn,
                char                    * mechanism,
                OraLdapHandle            cred,
                LDAPControl                     **serverctrls,
                LDAPControl                     **clientctrls
);

Parameters

The cred parameter is a SASL credential handle for the user. This handle can be managed using ora_ldap_create_cred_hdl(), ora_ldap_set_cred_props() and ora_ldap_free_cred_hdl() functions.

Supported SASL mechanisms:

  • DIGEST-MD5

    The Oracle Internet Directory SASL API supports the authentication-only mode of DIGEST-MD5. The other two authentication modes addressing data privacy and data integrity are yet to be supported.

    While authenticating against Oracle Internet Directory, the DN of the user has to be normalized before it is sent across to the server. This can be done either outside the SASL API using the ora_ldap_normalize_dn() function before the DN is passed on to the SASL API or with the SASL API by setting the ORA_LDAP_CRED_SASL_NORM_AUTHDN option in SASL credentials handle using ora_ldap_set_cred_handle().

  • EXTERNAL:

    The SASL API and SASL implementation in Oracle Internet Directory use SSL authentication as one of the external authentication mechanisms.

    Using this mechanism requires that the SSL connection (mutual authentication mode) be established to the directory server by using the ora_ldap_init_SSL() function. The ora_ldap_init_SASL() function can then be invoked with the mechanism argument as EXTERNAL. The directory server would then authenticate the user based on the user credentials in SSL connection.

8.2.6.2 ora_ldap_create_cred_hdl, ora_ldap_set_cred_props, ora_ldap_get_cred_props, and ora_ldap_free_cred_hdl

Use these functions to create and manage SASL credential handles. The ora_ldap_create_cred_hdl function should be used to create a SASL credential handle of certain type based on the type of mechanism used for SASL authentication. The ora_ldap_set_cred_props() function can be used to add relevant credentials to the handle needed for SASL authentication. The ora_ldap_get_cred_props() function can be used for retrieving the properties stored in the credential handle, and the ora_ldap_free_cred_hdl() function should be used to destroy the handle after its use.

Syntax

OraLdapHandle ora_ldap_create_cred_hdl
(
        OraLdapClientCtx * clientCtx,
        int                 credType
); 

OraLdapHandle ora_ldap_set_cred_props
(
        OraLdapClientCtx *   clientCtx,
        OraLdapHandle        cred,
        int                  String[],
        void             *   inProperty
); 
OraLdapHandle ora_ldap_get_cred_props
(
        OraLdapClientCtx *   clientCtx,
        OraLdapHandle   cred,
        int                     String[],
        void                   *   outProperty
); 

OraLdapHandle ora_ldap_free_cred_hdl 
(
        OraLdapClientCtx *   clientCtx,
        OraLdapHandle   cred
); 

Parameters

8.2.7 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 are described in Table 8-10.


See Also:

Chapter 3, "Extensions to the LDAP Protocol" for more information about controls.

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.

A set of controls that affect the entire session can be set using the ldap_set_option() function described in "ldap_get_option and ldap_set_option". 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.

One client control is defined in this chapter (described in the following section).

Client-Controlled Referral Processing As described previously in "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 referral chasing on per-request basis. A client control with an object identifier (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 LDAPControl 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 four-octet value that contains a set of flags. The ldctl_value.bv_len field must always be set to 4. The ldctl_value.bv_val field must point to a four-octet integer flags value. This 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 references 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 references are to be automatically chased.


See Also:

"Directory Schema Administration" in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for more information about object identifiers.

8.2.9 Performing LDAP Operations

Use the functions in this section to search the LDAP directory and to return a requested set of attributes for each entry matched.

8.2.9.1 ldap_search_ext, ldap_search_ext_s, ldap_search, and ldap_search_s

The ldap_search_ext() function initiates an asynchronous search operation and returns the constant LDAP_SUCCESS if the request was successfully sent, or another LDAP error code if not. If successful, ldap_search_ext() places the message id of the request in *msgidp. A subsequent call to ldap_result() 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 operation initiated. As for ldap_search_ext(), a subsequent call to ldap_result() can be used to obtain the result of the bind. In case of error, ldap_search() returns -1, setting the session 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 error code if it was not. Entries returned from the search, if any, are contained in the res parameter. This parameter is opaque to the caller. Entries, attributes, values, and so on, can be extracted by calling the parsing routines described in this section. The results contained in res should be freed when no longer in use by calling ldap_msgfree(), which is 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 additional parameter specifying a local timeout for the search. The local search timeout is used to limit the amount of time the API implementation waits for a search to complete. After the local search timeout expires, the API implementation sends an abandon operation to stop the search operation.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

int ldap_search_ext
(
LDAP            *ld,
const char      *base,
int             scope,
const char      *filter,
char            **attrs,
int             attrsonly,
LDAPControl     **serverctrls,
LDAPControl     **clientctrls,
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
);

Parameters

Table 8-12 lists and describes the parameters for search operations.

Table 8-12 Parameters for Search Operations

ParameterDescription
ld

The session handle.

base

The DN of the entry at which to start the search.

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 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 can be successfully used.

attrs

A NULL-terminated array of strings indicating which attributes 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 nonzero 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 infinite). 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() functions, 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 global 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 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 nonzero, 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.

res

For the synchronous calls, this is a result parameter which contains the results of the search upon completion of the call. If no results are returned, *res is set to NULL.

serverctrls

List of LDAP server controls.

clientctrls

List of client controls.

msgidp

This result parameter is set to the message id of the request if the ldap_search_ext() call succeeds.There are three options in the session handle ld which potentially affect how the search is performed. They are:

  • LDAP_OPT_SIZELIMIT—A limit on the number of entries to return from the search. A value of LDAP_NO_LIMIT (0) means no limit. Note that the value from the session handle is ignored when using the ldap_search_ext() or ldap_search_ext_s() functions.

  • LDAP_OPT_TIMELIMIT—A limit on the number of seconds to spend on the search. A value of LDAP_NO_LIMIT (0) means no limit. Note that the value from the session handle is ignored when using the ldap_search_ext() or ldap_search_ext_s() functions.

  • LDAP_OPT_DEREF—One of LDAP_DEREF_NEVER (0x00), LDAP_DEREF_SEARCHING (0x01), LDAP_DEREF_FINDING (0x02), or LDAP_DEREF_ALWAYS (0x03), specifying how aliases are handled during the search. The LDAP_DEREF_SEARCHING value means aliases are dereferenced during the search but not when locating the base object of the search. The LDAP_DEREF_FINDING value means aliases are dereferenced when locating the base object but not during the search.


8.2.9.4 ldap_compare_ext, ldap_compare_ext_s, ldap_compare, and ldap_compare_s

Use these routines to compare an attribute value assertion against an LDAP entry.

The ldap_compare_ext() function initiates an asynchronous compare operation and returns the constant LDAP_SUCCESS if the request was successfully sent, or another LDAP error code if not. If successful, ldap_compare_ext() places the message id of the request in *msgidp. A subsequent call to ldap_result() 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 operation initiated. As for ldap_compare_ext(), a subsequent call to ldap_result() can be used to obtain the result of the bind. In case of error, ldap_compare() returns -1, setting the session 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, either the constant LDAP_SUCCESS if the operation was successful, or another LDAP error code if it was not.

The ldap_compare_ext() and ldap_compare_ext_s() functions support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

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

Table 8-13 lists and describes the parameters for compare operations.

8.2.9.5 ldap_modify_ext, ldap_modify_ext_s, ldap_modify, and ldap_modify_s

Use these routines to modify an existing LDAP entry.

The ldap_modify_ext() function initiates an asynchronous modify operation and returns the constant LDAP_SUCCESS if the request was successfully sent, or another LDAP error code if not. If successful, ldap_modify_ext() places the message id of the request in *msgidp. A subsequent call to ldap_result() 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 operation initiated. As for ldap_modify_ext(), a subsequent call to ldap_result() can be used to obtain the result of the modify. In case of error, ldap_modify() returns -1, setting the session 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 error code if it was not.

The ldap_modify_ext() and ldap_modify_ext_s() functions support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

typedef struct ldapmod 
{
int             mod_op;
char            *mod_type;
union mod_vals_u
  {
  char            **modv_strvals;
  struct berval   **modv_bvals;
  } 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

Table 8-14 lists and describes the parameters for modify operations.


Table 8-15 lists and describes the fields in the LDAPMod structure.

Usage Notes

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 attribute is to be deleted, the mod_vals field can be set to NULL.

For LDAP_MOD_REPLACE modifications, the attribute has the listed values after the modification, having been created if necessary, or removed if the mod_vals field is NULL. All modifications are performed in the order in which they are listed.

8.2.9.6 ldap_rename and ldap_rename_s

Use these routines to change the name of an entry.

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 error code if not. If successful, ldap_rename() places the DN message id of the request in *msgidp. A subsequent call to ldap_result() 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 error code if it was not.

The ldap_rename() and ldap_rename_s() functions both support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

int ldap_rename
(
LDAP            *ld,
const char      *dn,
const char      *newrdn,
const char      *newparent,
int             deleteoldrdn,
LDAPControl     **serverctrls,
LDAPControl     **clientctrls,
int             *msgidp
);

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

Table 8-16 lists and describes the parameters for rename operations.

8.2.9.7 ldap_add_ext, ldap_add_ext_s, ldap_add, and ldap_add_s

Use these functions to add entries to the LDAP directory.

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 error code if not. If successful, ldap_add_ext() places the message id of the request in *msgidp. A subsequent call to ldap_result() can be used to obtain the result of the add.

Similar to ldap_add_ext(), the ldap_add() function initiates an asynchronous add operation and returns the message id of the operation initiated. As for ldap_add_ext(), a subsequent call to ldap_result() can be used to obtain the result of the add. In case of error, ldap_add() returns -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 error code if it was not.

The ldap_add_ext() and ldap_add_ext_s() functions support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

int ldap_add_ext
(
LDAP            *ld,
const char      *dn,
LDAPMod         **attrs,
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

Table 8-17 lists and describes the parameters for add operations.

Usage Notes

Note that the parent of the entry being added must already exist or the parent must be empty—that is, equal to the root DN—for an add to succeed.

8.2.9.8 ldap_delete_ext, ldap_delete_ext_s, ldap_delete, and ldap_delete_s

Use these functions to delete a leaf entry from the LDAP directory.

The ldap_delete_ext() function initiates an asynchronous delete operation and returns the constant LDAP_SUCCESS if the request was successfully sent, or another LDAP error code if not. If successful, ldap_delete_ext() places the message id of the request in *msgidp. A subsequent call to ldap_result() 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 operation initiated. As for ldap_delete_ext(), a subsequent call to ldap_result() can be used to obtain the result of the delete. In case of error, ldap_delete() returns -1, setting the session error parameters in the LDAP structure appropriately.

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 error code if it was not.

The ldap_delete_ext() and ldap_delete_ext_s() functions support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

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
);

int ldap_delete

(
LDAP            *ld,
const char      *dn
);

int ldap_delete_s
(
LDAP            *ld,
const char      *dn
);

Parameters

Table 8-18 lists and describes the parameters for delete operations.

Usage Notes

Note that the entry to delete must be a leaf entry—that is, it must have no children. Deletion of entire subtrees in a single operation is not supported by LDAP.

8.2.9.9 ldap_extended_operation and ldap_extended_operation_s

These routines enable extended LDAP operations to be passed to the server, providing a general protocol extensibility mechanism.

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 error code if not. If successful, ldap_extended_operation() places the message id of the request in *msgidp. A subsequent call to ldap_result() can be used to obtain the result of the extended operation which can be passed to ldap_parse_extended_result() to obtain the object identifier (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 error code if it was not. The retoid and retdata parameters are filled in with the OID and data from the response. If no OID or data was returned, these parameters are set to NULL.

The ldap_extended_operation() and ldap_extended_operation_s() functions both support LDAPv3 server controls and client controls.


See Also:

"Handling Errors and Parsing Results" for more information about possible errors and how to interpret them.

Syntax

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

Table 8-19 lists and describes the parameters for extended operations.

8.2.11 Obtaining Results and Peeking Inside LDAP Messages

Use the functions in this section to return the result of an operation initiated asynchronously. They identify messages by type and by ID.

8.2.11.1 ldap_result, ldap_msgtype, and ldap_msgid

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.

After 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. Therefore, a chain of messages returned by calling ldap_result() or by calling a synchronous search routine is never affected by subsequent LDAP API calls (except for ldap_msgfree() which is used to dispose of a chain of messages).

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.

Syntax

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

Table 8-21 lists and describes the parameters for obtaining results and peeling inside LDAP messages.

Usage Notes

Upon successful completion, ldap_result() returns the type of the first result returned in the res parameter. This is 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 is 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, then 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 is one of the types listed previously, or -1 on error.

ldap_msgid() returns the message ID associated with the LDAP message passed as a parameter, or -1 on error.

8.2.12 Handling Errors and Parsing Results

Use the functions in this section to extract information from results and to handle errors returned by other LDAP API routines.

8.2.12.1 ldap_parse_result, ldap_parse_sasl_bind_result, ldap_parse_extended_result, and ldap_err2string

Note that ldap_parse_sasl_bind_result() and ldap_parse_extended_result() must typically be used in addition to ldap_parse_result() to retrieve all the result information from SASL Bind and Extended Operations respectively.

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 error code if not. Note that the LDAP error 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 error 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.

Syntax

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 routines immediately following are deprecated. To learn more about them, see RFC 1823.

int ldap_result2error
(
LDAP            *ld,
LDAPMessage     *res,
int             freeit
);
void ldap_perror( LDAP *ld, const char *msg );

Parameters

Table 8-22 lists and describes parameters for handling errors and parsing results.

Table 8-22 Parameters for Handling Errors and Parsing Results

ParameterDescription
ld

The session handle.

res

The result of an LDAP operation as returned by ldap_result() or one of the synchronous API operation calls.

errcodep

This result parameter is filled in with the LDAP error code 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

In the case of a return of LDAP_NO_SUCH_OBJECT, this result parameter is filled in with a DN indicating how much of the name in the request was recognized. 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.

errmsgp

This result parameter is 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 is filled in with the contents of the referrals field from the LDAPMessage message, indicating 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.

serverctrlsp

This result parameter is filled in with an allocated array of controls copied out of the LDAPMessage message. The control array should be freed by calling ldap_controls_free() which was described earlier.

freeit

A Boolean that determines whether the res parameter is disposed of or not. Pass any nonzero value to have these routines free res after extracting the requested information. This is provided as a convenience; you can also use ldap_msgfree() to free the result later. If freeit is nonzero, the entire chain of messages represented by res is disposed of.

servercredp

For SASL bind results, this result parameter is filled in with the credentials 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.

retoidp

For extended results, this result parameter is 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. 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 is 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.

err

For ldap_err2string(), an LDAP error code, as returned by ldap_parse_result() or another LDAP API call.


Usage Notes

See RFC 1823 for a description of parameters peculiar to the deprecated routines.

8.2.13 Stepping Through a List of Results

Use the routines in this section to step through the list of messages in a result chain returned by ldap_result().

8.2.13.1 ldap_first_message and ldap_next_message

The result chain for search operations can 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 previously, 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

Table 8-23 lists and describes the parameters for stepping through a list of results.

Usage Notes

ldap_first_message() and ldap_next_message() returns 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 is set to indicate the error.

If successful, ldap_count_messages() returns the number of messages contained in a chain of results; if an error occurs such as the res parameter 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().

8.2.14 Parsing Search Results

Use the functions in this section to parse the entries and references returned by ldap_search functions. These results are returned in an opaque structure that may be accessed by calling the routines described in this section. Routines are provided to step through the entries and references returned, step through the attributes of an entry, retrieve the name of an entry, and retrieve the values associated with a given attribute in an entry.

8.2.14.1 ldap_first_entry, ldap_next_entry, ldap_first_reference, ldap_next_reference, ldap_count_entries, and ldap_count_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

Table 8-24 lists and describes the parameters or retrieving entries and continuation references from a search result chain, and for counting entries returned.

Usage Notes

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 is set to indicate 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, -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.

8.2.14.2 ldap_first_attribute and ldap_next_attribute

Use the functions in this section to step through the list of attribute types returned with an entry.

Syntax

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

Table 8-25 lists and describes the parameters for stepping through attribute types returned with an entry.

Usage Notes

ldap_first_attribute() and ldap_next_attribute() returns NULL when the end of the attributes is reached, or if there is an error. In the latter case, the error parameters in the session handle ld are set to indicate 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() allocates and returns 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.

8.2.14.3 ldap_get_values, ldap_get_values_len, ldap_count_values, ldap_count_values_len, ldap_value_free, and ldap_value_free_len

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.

Syntax

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 );
void ldap_value_free_len( struct berval **vals );

Parameters

Table 8-26 lists and describes the parameters for retrieving and counting attribute values.

Usage Notes

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.

8.2.14.4 ldap_get_dn, ldap_explode_dn, ldap_explode_rdn, and ldap_dn2ufn

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.

Syntax

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 );

Parameters

Table 8-27 lists and describes the parameters for retrieving, exploding, and converting entry names.

Usage Notes

ldap_get_dn() returns NULL if a DN parsing error occurs. The function sets 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.

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 a user friendly format. The UFN returned is newly allocated space that should be freed by a call to ldap_memfree() when no longer in use.

8.2.14.6 ldap_parse_reference

Use ldap_parse_reference() to extract referrals and controls from a SearchResultReference message.

Syntax

int ldap_parse_reference
(
LDAP            *ld,
LDAPMessage     *ref,
char            ***referralsp,
LDAPControl     ***serverctrlsp,
int             freeit
);

Parameters

Table 8-29 lists and describes parameters for extracting referrals and controls from a SearchResultReference message.

Usage Notes

ldap_parse_reference() returns an LDAP error code that indicates whether the reference could be successfully parsed (LDAP_SUCCESS if all goes well).

8.3 Sample C API Usage

The first three examples show how to use the C API both with and without SSL and for SASL authentication. More complete examples are given in RFC 1823. The sample code for the command-line tool to perform an LDAP search also demonstrates use of the API in both the SSL and the non-SSL mode.

This section contains these topics:

8.3.3 C API Usage for SASL-Based DIGEST-MD5 Authentication

This sample program illustrates the usage of LDAP SASL C-API for SASL-based DIGEST-MD5 authentication to a directory server.

/*
   EXPORT FUNCTION(S)
     NONE

   INTERNAL FUNCTION(S)
     NONE

   STATIC FUNCTION(S)
     NONE

   NOTES
     Usage:
      saslbind -h ldap_host -p ldap_port -D authentication_identity_dn \
               -w password  
      options 
       -h     LDAP host
       -p     LDAP port
       -D     DN of the identity for authentication
       -p     Password

       Default SASL authentication parameters used by the demo program
       SASL Security Property :    Currently only "auth" security property 
                                   is supported by the C-API. This demo
                                   program uses this security property.
       SASL Mechanism         :    Supported mechanisms by OID
                                   "DIGEST-MD5" - This demo program 
                                                  illustrates it's usage.
                                   "EXTERNAL" - SSL authentication is used.
                                                (This demo program does 
                                                 not illustrate it's usage.)
       Authorization identity :    This demo program does not use any
                                    authorization identity.

   MODIFIED   (MM/DD/YY)
   ******      06/12/03 - Creation

*/

/*---------------------------------------------------------------------------
                     PRIVATE TYPES AND CONSTANTS
  ---------------------------------------------------------------------------*/
                
/*---------------------------------------------------------------------------
                     STATIC FUNCTION DECLARATIONS 
  ---------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>


static int ldap_version = LDAP_VERSION3;

main (int argc, char **argv)
{
  LDAP*           ld;
  extern char*    optarg;
  char*           ldap_host = NULL;
  char*           ldap_bind_dn = NULL;
  char*           ldap_bind_pw = NULL;
  int             authmethod = 0;
  char            ldap_local_host[256] = "localhost";
  int             ldap_port = 3060;
  char*           authcid = (char *)NULL;
  char*           mech = "DIGEST-MD5"; /* SASL mechanism */
  char*           authzid = (char *)NULL;
  char*           sasl_secprops = "auth";
  char*           realm = (char *)NULL;
  int             status = LDAP_SUCCESS;
  OraLdapHandle   sasl_cred = (OraLdapHandle )NULL;
  OraLdapClientCtx *cctx = (OraLdapClientCtx *)NULL;
  int              i = 0;


    while (( i = getopt( argc, argv,
            "D:h:p:w:E:P:U:V:W:O:R:X:Y:Z"
            )) != EOF ) {
        switch( i ) {

        case 'h':       /* ldap host */
            ldap_host = (char *)strdup( optarg );
            break;
        case 'D':       /* bind DN */
            authcid = (char *)strdup( optarg );
            break;
            
        case 'p':       /* ldap port */
            ldap_port = atoi( optarg );
            break;
        case 'w':       /* Password */
            ldap_bind_pw = (char *)strdup( optarg );
            break;

    default:
            printf("Invalid Arguments passed\n" );
        }
    }


  /* Get the connection to the LDAP server */
  if (ldap_host == NULL)
    ldap_host = ldap_local_host;

  if ((ld = ldap_open (ldap_host, ldap_port)) == NULL)
  {
    ldap_perror (ld, "ldap_init");
    exit (1);
  }

  /* Create the client context needed by LDAP C-API Oracle Extension functions*/
  status = ora_ldap_init_clientctx(&cctx);

  if(LDAP_SUCCESS != status) {
     printf("Failed during creation of client context \n");
     exit(1);
  }

  /* Create SASL credentials */
  sasl_cred = ora_ldap_create_cred_hdl(cctx, ORA_LDAP_CRED_HANDLE_SASL_MD5);

  ora_ldap_set_cred_props(cctx, sasl_cred, ORA_LDAP_CRED_SASL_REALM, 
      (void *)realm);
  ora_ldap_set_cred_props(cctx, sasl_cred, ORA_LDAP_CRED_SASL_AUTH_PASSWORD, 
      (void *)ldap_bind_pw);
  ora_ldap_set_cred_props(cctx, sasl_cred, ORA_LDAP_CRED_SASL_AUTHORIZATION_ID,
      (void *)authzid);
  ora_ldap_set_cred_props(cctx, sasl_cred, ORA_LDAP_CRED_SASL_SECURITY_PROPERTIES, 
      (void *)sasl_secprops);

  /* If connecting to the directory using SASL DIGEST-MD5, the Authentication ID 
     has to be normalized before it's sent to the server,
     the LDAP C-API does this normalization based on the following flag set in
     SASL credential properties */
  ora_ldap_set_cred_props(cctx, sasl_cred, ORA_LDAP_CRED_SASL_NORM_AUTHDN, (void *)NULL);
  
  /* SASL Authetication to LDAP Server */
  status = (int)ora_ldap_init_SASL(cctx, ld, (char *)authcid, (char *)ORA_LDAP_SASL_MECH_DIGEST_MD5,
                                     sasl_cred, NULL, NULL);

  if(LDAP_SUCCESS == status) {
     printf("SASL bind successful \n" );
  }else {
     printf("SASL bind failed with status :  %d\n", status);
  }

  /* Free SASL Credentials */
  ora_ldap_free_cred_hdl(cctx, sasl_cred);

  status = ora_ldap_free_clientctx(cctx);

  /* Unbind from LDAP server */
  ldap_unbind (ld);

  return (0);
}


/* end of file saslbind.c */

8.3.4 Setting and Using a Callback Function to Get Credentials When Chasing Referrals

To set the callback function, you use ldap_set_rebind_proc(). The callback function is used only if LDAP_OPT_REFERRALS is set using ldap_set_option(). If ldap_set_rebind_proc() is not called, then the library uses anonymous bind to connect to a new server while chasing LDAP referrals.

/* referralsample.c - Sample program to demonstrate the usage of ldap_set_rebind_proc() for referrals */
 
#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>
 
 
/*
* Prints the Entry DNs of the search result
*/
void print_entry_dns( LDAP *ld, LDAPMessage *result )
{
   LDAPMessage     *e;
   char            *dn;
 
   for ( e = ldap_first_entry( ld, result ); e != NULL;
      e = ldap_next_entry(ld, e ) )
   {
       if ( (dn = ldap_get_dn( ld, e )) != NULL ) {
           printf( "dn: %s\n\n", dn );
           ldap_memfree( dn );
       }
       else {
           ldap_perror( ld, "ldap_get_dn" );
       }
   }
}
 
/*
* Rebind function for providing the credentials to bind referral servers
*/
int getbindcredentials(LDAP *ld, char **binddn, char **bindpwd, int *authmethod, int freeit)
{
   if (freeit == 0) {
   /* In this example bind credentials are static.  Typically, Bind credentials are fetched from wallet or
some other means for the server information in input session handle */
 
       *binddn = "cn=orcladmin";
       *bindpwd = "xyz";
       *authmethod = LDAP_AUTH_SIMPLE;
   }
   else {
   /* In this example there is no memory allocation.
      If the memory is allocated for binddn/bindpwd/authmehod, they should be freed here */
 
       *binddn = NULL;
       *bindpwd = NULL;
       *authmethod = 0;
   }
 
   return 0;
}
 
main()
{
   char            ldaphost[] = "localhost";
   char            binddn[] = "cn=orcladmin";
   char            bindpwd[] = "password";
   int             ldapport = 3060;
   char            searchbase[] = "dc=oracle,dc=com";
   char            filter[] = "objectclass=*";
   int             scope = LDAP_SCOPE_SUBTREE;
 
   LDAP           *ld;
   LDAPMessage    *result;
   int             ret = 0;
 
 
   if ( (ld = ldap_open( ldaphost, ldapport )) == NULL) {
       printf( "ldap_open: Connection failed\n" );
       exit( 1 );
   }
 
   if ( ldap_simple_bind_s(ld, binddn, bindpwd) != LDAP_SUCCESS ) {
       ldap_perror(ld, "ldap_simple_bind_s");
       exit( 1 );
   }
 
   /* Set this option to connect to the referrals */
   ldap_set_option (ld, LDAP_OPT_REFERRALS, (void *)1);
 
   /* set the function pointer which provides the bind credentials for referral server */
   ldap_set_rebind_proc(ld,  (int (*)(LDAP*, char**, char**, int*, int))getbindcredentials);
 
 
   ret = ldap_search_s( ld, searchbase, scope, filter, NULL, 0, &result );
   if(LDAP_SUCCESS != ret) {
     ldap_perror(ld, "ldap_search_s");
     exit( 1 );
   }
 
   print_entry_dns(ld, result);
 
  ldap_unbind(ld);
  return(0);
}

8.4 Required Header Files and Libraries for the C API

To build applications with the C API, you need to:

  • Include the header file located at $ORACLE_HOME/ldap/public/ldap.h.

  • Dynamically link to the library located at

    • $ORACLE_HOME/lib/libclntsh.so.10.1 on UNIX operating systems

    • %ORACLE_HOME%\bin\oraldapclnt10.dll on Windows operating systems

8.5 Dependencies and Limitations of the C API

This API can work against any release of Oracle Internet Directory. It requires either an Oracle environment or, at minimum, globalization support and other core libraries.

To use the different authentication modes in SSL, the directory server requires corresponding configuration settings.


See Also:

Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for details about how to set the directory server in various SSL authentication modes.

Oracle Wallet Manager is required for creating wallets if you are using the C API in SSL mode.

TCP/IP Socket Library is required.

The following Oracle libraries are required:

Sample libraries are included in the release for the sample command line tool. You should replace these libraries with your own versions of the libraries.

The product supports only those authentication mechanisms described in LDAP SDK specifications (RFC 1823).

All strings input to the C API must be in UTF-8 format. If the strings are not in the UTF-8 format, you can use the OCI function OCINlsCharSetConvert to perform the conversion. Please see the Oracle Call Interface Programmer's Guide in the Oracle Database Library at http://www.oracle.com/technology/documentation.

PK q0N0PKؐj?OEBPS/provisng.htm] Developing Provisioning-Integrated Applications

7 Developing Provisioning-Integrated Applications

As of 10g (10.1.4.0.1), new APIs were added for developing provisioning-integrated applications. Nothing has changed for 11g Release 1 (11.1.1). Please refer to: Oracle Fusion Middleware Administrator's Guide for Oracle Directory Integration Platform.

PKHPKؐj?OEBPS/orcl_ext.htmZ Developing Applications With Oracle Extensions to the Standard APIs

4 Developing Applications With Oracle Extensions to the Standard APIs

This chapter introduces the Oracle extensions to the Java and PL/SQL LDAP APIs. Chapter 5 explains how the Java extensions are used. Chapter 6 is about the PL/SQL extensions. Oracle does not support extensions to the C API.

This chapter contains these topics:

4.1 Sample Code

Sample code is available at this URL:

http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications—Fusion Middleware.

4.2 Using Oracle Extensions to the Standard APIs

The APIs that Oracle has added to the existing APIs fulfill these functions:

  • User management

    Applications can set or retrieve various user properties

  • Group management

    Applications can query group properties

  • Realm management

    Applications can set or retrieve properties about identity management realms

  • Server discovery management

    Applications can locate a directory server in the Domain Name System (DNS)

Subsequent sections examine each of these functions in detail. Note that applications must use the underlying APIs for such common tasks as establishing and closing connections and looking up directory entries not searchable with the API extensions.

Figure 4-1 shows what program flow looks like when the API extensions are used.

As Figure 4-1 shows, an application first establishes a connection to Oracle Internet Directory. It can then use the standard API functions and the API extensions interchangeably.

4.3 Creating an Application Identity in the Directory

Before an application can use the LDAP APIs and their extensions, it must establish an LDAP connection. After it establishes a connection, it must have permission to perform operations. But neither task can be completed if the application lacks an identity in the directory.

4.3.2 Assigning Privileges to an Application Identity

To learn about the privileges available to an application, see the chapter about delegating privileges for an Oracle technology deployment in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory. After identifying the right set of privileges, add the application entity DN to the appropriate directory groups. The reference just provided explains how to perform this task using either Oracle Directory Services Manager or the ldapmodify command.

4.4 Managing Users

This section describes user management features of the LDAP APIs.

Directory-enabled applications need to perform the following operations:

  • Retrieve properties of user entries

    These properties are stored as attributes of the user entry itself—in the same way, for example, that a surname or a home address is stored.

  • Retrieve extended user preferences

    These preferences apply to a user but are stored in a DIT different from the DIT containing user entries. Extended user preferences are either user properties common to all applications or user properties specific to an application. Those of the first type are stored in a common location in the Oracle Context. Those of the second type are stored in the application-specific DIT.

  • Query the group membership of a user

  • Authenticate a user given a simple name and credential

    Typically an application uses a fully qualified DN, GUID, or simple user name to identify a user. In a hosted environment, the application may use both a user name and a realm name for identification.

4.5 Managing Groups

Groups are modeled in Oracle Internet Directory as a collection of distinguished names. Directory-enabled applications must access Oracle Internet Directory to obtain the properties of a group and to verify that a given user is a member of that group.

A group is typically identified by one of the following:

  • A fully qualified LDAP distinguished name

  • A global unique identifier

  • A simple group name along with a subscriber name

4.6 Managing Realms

An identity management realm is an entity or organization that subscribes to the services offered in the Oracle product stack. Directory-enabled applications must access Oracle Internet Directory to obtain realm properties such as user search base or password policy.

A realm is typically identified by one of the following:

  • A fully qualified LDAP distinguished name

  • A global unique identifier

  • A simple enterprise name

4.7 Discovering a Directory Server

Directory server discovery (DSD) enables automatic discovery of the Oracle directory server by directory clients. It enables deployments to manage the directory host name and port number information in the central DNS server. All directory clients perform a DNS query at runtime and connect to the directory server. Directory server location information is stored in a DNS service location record (SRV).

An SRV contains:

  • The DNS name of the server providing LDAP service

  • The port number of the corresponding port

  • Any parameters that enable the client to choose an appropriate server from multiple servers

DSD also allows clients to discover the directory host name information from the ldap.ora file itself.

This section contains these topics:


See Also:

  • "Discovering LDAP Services with DNS" by Michael P. Armijo at this URL:

    http://www.ietf.org.
    
  • "A DNS RR for specifying the location of services (DNS SRV)", Internet RFC 2782 at the same URL.


4.7.1 Benefits of Oracle Internet Directory Discovery Interfaces

Typically, the LDAP host name and port information is provided statically in a file called ldap.ora which is located on the client in $ORACLE_HOME/network/admin. For large deployments with many clients, this information becomes very cumbersome to manage. For example, each time the host name or port number of a directory server is changed, the ldap.ora file on each client must be modified.

Directory server discovery eliminates the need to manage the host name and port number in the ldap.ora file. Because the host name information resides on one central DNS server, the information must be updated only once. All clients can then discover the new host name information dynamically from the DNS when they connect to it.

DSD provides a single interface to obtain directory server information without regard to the mechanism or standard used to obtain it. Currently, Oracle directory server information can be obtained either from DNS or from ldap.ora using a single interface.

4.7.2 Usage Model for Discovery Interfaces

The first step in discovering host name information is to create a discovery handle. A discovery handle specifies the source from which host name information is discovered. In case of the Java API, the discovery handle is created by creating an instance of the oracle.ldap.util.discovery.DiscoveryHelper class.

DiscoveryHelper disco = new DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);

The argument DiscoveryHelper.DNS_DISCOVER specifies the source. In this case the source is DNS.

Each source may require some inputs to be specified for discovery of host name information. In the case of DNS these inputs are:

  • domain name

  • discover method

  • SSL mode

Detailed explanation of these options is given in "Determining Server Name and Port Number From DNS".

// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com");
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD
   ,DiscoveryHelper.USE_INPUT_DN_METHOD);
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");

Now the information can be discovered.

// Call the discover method
disco.discover(reshdl);

The discovered information is returned in a result handle (reshdl). Now the results can be extracted from the result handle.

ArrayList result =
(ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
if (result != null)
{
   if (result.size() == 0) return;
   System.out.println("The hostnames are :-");
   for (int i = 0; i< result.size();i++)
   {
      String host = (String)result.get(i);
      System.out.println((i+1)+".'"+host+"'");
   }
}

4.7.3 Determining Server Name and Port Number From DNS

Determining a host name and port number from a DNS lookup involves obtaining a domain and then searching for SRV resource records based on that domain. If there is more than one SRV resource record, they are sorted by weight and priority. The SRV resource records contain host names and port numbers required for connection. This information is retrieved from the resourcerecords and returned to the user.

There are three approaches for determining the domain name required for lookup:

  • Mapping the distinguished name (DN) of the naming context

  • Using the domain component of local machine

  • Looking up the default SRV record in the DNS

4.7.5 Programming Interfaces for DNS Server Discovery

The programming interface provided is a single interface to discover directory server information without regard to the mechanism or standard used to obtain it. Information can be discovered from various sources. Each source can use its own mechanism to discover the information. For example, the LDAP host and port information can be discovered from the DNS acting as the source. Here DSD is used to discover host name information from the DNS.


See Also:

For detailed reference information and class descriptions, refer to the Javadoc located on the product CD.

PK0ZZPKؐj?OEBPS/dipapiref.htm Oracle Directory Integration Platform PL/SQL API Reference

13 Oracle Directory Integration Platform PL/SQL API Reference

This chapter describes the registration API for the Oracle Directory Provisioning Integration Service. It contains the following sections:

13.1 Versioning of Provisioning Files and Interfaces

In release 9.0.2, the default interface version was version 1.1. In releases 9.0.4 and 10.1.2.0.0, the interface version defaults to version 2.0. Release 10.1.2.0.1 adds yet a third version. The administrator can use any one of these.

13.2 Extensible Event Definition Configuration

This feature is only for outbound events. It addresses the ability to define a new event at run time so that the provisioning integration service can interpret a change in Oracle Internet Directory and determine whether an appropriate event is to be generated and propagated to an application. The following events are the only configured events at installation time.

An event definition (entry) consists of the following attributes.

  • Event object type (orclODIPProvEventObjectType): This specifies the type of object the event is associated with. For example, the object could be a USER, GROUP, or IDENTITY.

  • LDAP change type (orclODIPProvEventChangeType): This indicates that all kinds of LDAP operations can generate an event for this type of object. (e.g ADD, MODIFY, DELETE)

  • Event criteria (orclODIPProvEventCriteria): The additional selection criteria that qualify an LDAP entry to be of a specific object type. For example, Objectclass=orclUserV2 means that any LDAP entry that satisfies this criteria can be qualified as this Object Type and any change to this entry can generate appropriate events.

The object class that holds these attributes is orclODIPProvEventTypeConfig. The container cn=ProvisioningEventTypeConfig,cn=odi,cn=oracle internet directory is used to store all the event type configurations.

Table 13-1 lists the event definitions predefined as a part of the installation.

The container cn=ProvisioningEventTypeConfig,cn=odi,cn=oracle internet directory is used to store all the event definition configurations. LDAP configuration of the predefined event definitions is as follows:

dn: orclODIPProvEventObjectType=ENTRY,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: ENTRY
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=*
objectclass: orclODIPProvEventTypeConfig

dn: orclODIPProvEventObjectType=USER,cn=ProvisioningEventTypeConfig,cn=odi,cn=oracle internet directory
orclODIPProvEventObjectType: USER
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=InetOrgPerson
orclODIPProvEventCriteria: objectclass=orcluserv2
objectclass: orclODIPProvEventTypeConfig

dn: orclODIPProvEventObjectType=IDENTITY,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: IDENTITY
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=inetorgperson
orclODIPProvEventCriteria: objectclass=orcluserv2
objectclass: orclODIPProvEventTypeConfig

dn: orclODIPProvEventObjectType=GROUP,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: GROUP
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=orclgroup
orclODIPProvEventCriteria: objectclass=groupofuniquenames
objectclass: orclODIPProvEventTypeConfig

dn: orclODIPProvEventObjectType=SUBSCRIPTION,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: SUBSCRIPTION
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=orclservicerecepient
objectclass: orclODIPProvEventTypeConfig

dn: orclODIPProvEventObjectType=SUBSCRIBER,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: SUBSCRIBER
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=orclsubscriber
objectclass: orclODIPProvEventTypeConfig

To define a new event of Object type XYZ (which is qualified with the object class objXYZ), create the following entry in Oracle Internet Directory. The DIP server recognizes this new event definition and propagates events if necessary to applications that subscribe to this event.

dn: orclODIPProvEventObjectType=XYZ,cn=ProvisioningEventTypeConfig,cn=odi, cn=oracle internet directory
orclODIPProvEventObjectType: XYZ
orclODIPProvEventLDAPChangeType: Add
orclODIPProvEventLDAPChangeType: Modify
orclODIPProvEventLDAPChangeType: Delete
orclODIPProvEventCriteria: objectclass=objXYZ
objectclass: orclODIPProvEventTypeConfig

This means that if an LDAP entry with the object class objXYZ is added, modified, or deleted, DIP propagates the XYZ_ADD, XYZ_MODIFY, or XYZ_DELETE event to any application concerned.

13.3 Inbound and Outbound Events

An application can register as a supplier as and as a consumer of events. The provisioning subscription profile has the attributes described in Table 13-2.

Table 13-2 Attributes of the Provisioning Subscription Profile

AttributeDescription
EventSubscriptions

Outbound events only (multivalued).

Events for which DIP should send notification to this application. The format of this string is [USER]GROUP]:[domain_of_interest]:[DELETE|ADD|MODIFY(list_of_attributes_separated_by_comma)]

Multiple values may be specified by listing the string multiple times, each time with different values. If parameters are not specified, the following defaults are assumed: USER:organization_DN:DELETEGROUP:organization_DN:DELETE—that is, send user and group delete notifications under the organization DN.

MappingRules

Inbound events Only (multivalued).

This attribute is used to map the type of object received from an application and a qualifying filter condition to determine the domain of interest for this event. The mapping takes this form:

OBJECT_TYPE: Filter_condition: domain_of_interest

Multiple rules are allowed. In the mapping EMP:cn=users,dc=example,dc=com, the object type received is EMP. The event is meant for the domain cn=users,dc=example,dc=com. In the mapping EMP:l=AMERICA:l=AMER,cn=users,dc=example,dc=com, the object type received is EMP. The event is meant for the domain l=AMER,cn=users,dc=example,dc=com.

permittedOperations

Inbound events only (multi valued).

This attribute is used to define the types of events an application is privileged to send to the provisioning integration service. The mapping takes this form:

Event_Object: affected_domain:operation(attributes, . . . )

In the mapping IDENTITY:cn=users,dc=example,dc=com:ADD(*) the IDENTITY_ADD event is allowed for the specified domain and all attributes are also allowed. In the mapping IDENTITY:cn=users,dc=example,dc=com:MODIFY(cn,sn.mail,telephonenumber), the IDENTITY_MODIFY event is allowed only for the attributes in the list. Any extra attributes are silently ignored.


13.4 PL/SQL Bidirectional Interface (Version 3.0)

Before attempting to use Version 3.0 of the PL/SQL interface, please refer to:

The PL/SQL callback interface requires you to develop a PL/SQL package that Oracle Directory Provisioning Integration Service invokes in the application specific database. Choose any name for the package, but be sure to use the same name when you register the package at subscription time. Implement the package by using the following PL/SQL package specification:

DROP TYPE LDAP_EVENT_LIST_V3;
DROP TYPE LDAP_EVENT_V3;
DROP TYPE LDAP_EVENT_STATUS_LIST_V3;
DROP TYPE LDAP_ATTR_LIST_V3;
DROP TYPE LDAP_ATTR_V3;
DROP TYPE LDAP_ATTR_VALUE_LIST_V3;
DROP TYPE LDAP_ATTR_VALUE_V3;
--------------------------------------------------------------------------------------------------
-- Name: LDAP_ATTR_VALUE_V3
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains values of an attribute. A list of one or
more of this object is passed in any event.
---------------------------------------------------------------------------------------------------
 
CREATE TYPE LDAP_ATTR_VALUES_V3 AS OBJECT (
     attr_value       VARCHAR2(4000),
     attr_bvalue      RAW(2048),
     attr_value_len   INTEGER
);
 
GRANT EXECUTE ON LDAP_ATTR_VALUE_V3 to public;
 
CREATE TYPE LDAP_ATTR_VALUE_LIST_V3 AS TABLE OF LDAP_ATTR_VALUE_V3;
/
GRANT EXECUTE ON LDAP_ATTR_VALUE_LIST_V3 to public;
--------------------------------------------------------------------------------------------------
-- Name: LDAP_ATTR_V3
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains details regarding an attribute. A list of
one or more of this object is passed in any event.
---------------------------------------------------------------------------------------------------
CREATE TYPE LDAP_ATTR_V3 AS OBJECT (
     attr_name        VARCHAR2(256),
     attr_type        INTEGER ,
     attr_mod_op      INTEGER,
     attr_values      LDAP_ATTR_VALUE_LIST_V3
);
 
GRANT EXECUTE ON LDAP_ATTR_V3 to public;
 
CREATE TYPE LDAP_ATTR_LIST_V3 AS TABLE OF LDAP_ATTR_V3;
/
GRANT EXECUTE ON LDAP_ATTR_LIST_V3 to public;
---------------------------------------------------------------------------------------------------
-- Name: LDAP_EVENT_V3
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains event information plus the attribute List.
---------------------------------------------------------------------------------------------------
 
CREATE TYPE LDAP_EVENT_V3 AS OBJECT (
          event_type  VARCHAR2(32),
          event_id    VARCHAR2(32),
          event_src   VARCHAR2(1024),
          event_time  VARCHAR2(32),
          object_name VARCHAR2(1024),
          object_type VARCHAR2(32),
          object_guid VARCHAR2(32),
          object_dn   VARCHAR2(1024),
          profile_id  VARCHAR2(1024),
          attr_list   LDAP_ATTR_LIST_V3 ) ;
/
 
GRANT EXECUTE ON LDAP_EVENT_V3 to public;
CREATE TYPE LDAP_EVENT_LIST_V3 AS TABLE OF LDAP_EVENT_V3;
/
GRANT EXECUTE ON LDAP_EVENT_LIST_V3 to public;
---------------------------------------------------------------------------------------------------
-- Name: LDAP_EVENT_STATUS_V3
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains information that is sent by the consumer
of an event to the supplier in response to the actual event.
 ---------------------------------------------------------------------------------------------------
 
CREATE TYPE LDAP_EVENT_STATUS_V3 AS OBJECT (
          event_id     VARCHAR2(32),
          status       VARCHAR2(32),
          status_msg   VARCHAR2(2048),
          object_guid  VARCHAR(32)
) ;
/
 
GRANT EXECUTE ON LDAP_EVENT_STATUS_V3 to public;
CREATE TYPE LDAP_EVENT_STATUS_LIST_V3 AS TABLE OF LDAP_EVENT_STATUS_V3;
/
GRANT EXECUTE ON LDAP_EVENT_STATUS_LIST_V3 to public;
---------------------------------------------------------------------------------------------------
-- Name: LDAP_NTFY
-- DESCRIPTION: This is the interface to be implemented by provisioning integrated
applications to send information to and receive information from the directory.
The name of the package can be customized as needed. The function and procedure
names within this package should not be changed.
 ---------------------------------------------------------------------------------------------------
 
CREATE OR REPLACE PACKAGE LDAP_NTFY AS
 
    -- The Predefined Event Types

    ENTRY_ADD     CONSTANT VARCHAR2 (32) :='ENTRY_ADD';
    ENTRY_DELETE  CONSTANT VARCHAR2 (32) :='ENTRY_DELETE';
    ENTRY_MODIFY  CONSTANT VARCHAR2 (32) :='ENTRY_MODIFY';
 
    USER_ADD     CONSTANT VARCHAR2 (32) :='USER_ADD';
    USER_DELETE  CONSTANT VARCHAR2 (32) :='USER_DELETE';
    USER_MODIFY  CONSTANT VARCHAR2 (32) :='USER_MODIFY';
 
    IDENTITY_ADD     CONSTANT VARCHAR2 (32) :='IDENTITY_ADD';
    IDENTITY_DELETE  CONSTANT VARCHAR2 (32) :='IDENTITY_DELETE';
    IDENTITY_MODIFY  CONSTANT VARCHAR2 (32) :='IDENTITY_MODIFY';
 
    GROUP_ADD     CONSTANT VARCHAR2 (32) :='GROUP_ADD';
    GROUP_DELETE  CONSTANT VARCHAR2 (32) :='GROUP_DELETE';
    GROUP_MODIFY  CONSTANT VARCHAR2 (32) :='GROUP_MODIFY';
 
    SUBSCRIPTION_ADD     CONSTANT VARCHAR2(32) :='SUBSCRIPTION_ADD';
    SUBSCRIPTION_DELETE  CONSTANT VARCHAR2(32) :='SUBSCRIPTION_DELETE';
    SUBSCRIPTION_MODI    CONSTANT VARCHAR2(32) :='SUBSCRIPTION_MODIFY';
 
    SUBSCRIBER_ADD     CONSTANT VARCHAR2(32) :='SUBSCRIBER_ADD';
    SUBSCRIBER_DELETE  CONSTANT VARCHAR2(32) :='SUBSCRIBER_DELETE';
    SUBSCRIBER_MODIFY  CONSTANT VARCHAR2(32) :='SUBSCRIBER_MODIFY';
 
    -- The Attribute Type

    ATTR_TYPE_STRING            CONSTANT NUMBER  := 0;
    ATTR_TYPE_BINARY            CONSTANT NUMBER  := 1;
    ATTR_TYPE_ENCRYPTED_STRING  CONSTANT NUMBER  := 2;
 
    -- The Attribute Modification Type

    MOD_ADD      CONSTANT NUMBER  := 0;
    MOD_DELETE   CONSTANT NUMBER  := 1;
    MOD_REPLACE  CONSTANT NUMBER  := 2;
 
    -- The Event dispostions constants
 
    EVENT_SUCCESS            CONSTANT VARCHAR2(32)  :='EVENT_SUCCESS';
    EVENT_IN_PROGRESS        CONSTANT VARCHAR2(32)  :='EVENT_IN_PROGRESS';
    EVENT_USER_NOT_REQUIRED  CONSTANT VARCHAR2(32)  :='EVENT_USER_NOT_REQUIRED';
    EVENT_ERROR              CONSTANT VARCHAR2(32)  :='EVENT_ERROR';
    EVENT_ERROR_ALERT        CONSTANT VARCHAR2(32)  :='EVENT_ERROR_ALERT';
    EVENT_ERROR_ABORT        CONSTANT VARCHAR2(32)  :='EVENT_ERROR_ABORT';
 
    -- The Actual Callbacks
 
    FUNCTION GetAppEvents (events OUT LDAP_EVENT_LIST_V3)
    RETURN NUMBER;
 
    -- Return CONSTANTS
    EVENT_FOUND      CONSTANT NUMBER:= 0;
    EVENT_NOT_FOUND  CONSTANT NUMBER:= 1403;

If the provisioning server is unable to process an inbound event, it triggers an EVENT_ERROR_ALERT status, which generates a trigger in Oracle Enterprise Manager.

If the provisioning server is able to process the event, but finds that the event cannot be processed—for example, the user to be modified, subscribed, or deleted does not exist—it responds with EVENT_ERROR to indicate to the application that something is wrong. It is again up to the application to handle the status event.

EVENT_ERROR means no errors in directory operations. The event cannot be processed for other reasons.

-- PutAppEventStatus() : DIP Server invokes this callback in the remote Data
base after processing an event it had received using the GetAppEvents()
callback.  For every event received, the DIP server sends the status event
back after processing the event.  This API will NOT be required by the
Oracle Collaboration Suite release 3.0 components.

PROCEDURE PutAppEventStatus (event_status IN LDAP_EVENT_STATUS_LIST_V3);
 
-- PutOIDEvents() : DIP Server invokes this API in the remote Database. DIP
server sends event to applications using this callback. It also expects a status
event object in response as an OUT parameter. This API needs to be implemented
by all the Oracle Collaboration Suite release 3.0 components.

PROCEDURE PutOIDEvents (event         IN  LDAP_EVENT_LIST_V3,
                       event_status  OUT LDAP_EVENT_STATUS_LIST_V3);
 
END LDAP_NTFY;
/

13.5 PL/SQL Bidirectional Interface (Version 2.0)

The PL/SQL callback interface requires that you develop a PL/SQL package that the provisioning integration service invokes in the application-specific database. Choose any name for the package, but be sure to use the same name when you register the package at subscription time. Implement the package using the following PL/SQL package specification:

DROP TYPE LDAP_EVENT;
DROP TYPE LDAP_EVENT_STATUS;
DROP TYPE LDAP_ATTR_LIST;
DROP TYPE LDAP_ATTR;
--------------------------------------------------------------------------------
-- Name: LDAP_ATTR
-- Data Type: OBJECT

DESCRIPTION: This structure contains details regarding an attribute. A list of one
--           or more of this object is passed in any event.
---------------------------------------------------------------------------------------------------
CREATE TYPE LDAP_ATTR AS OBJECT (
     attr_name        VARCHAR2(256),
     attr_value       VARCHAR2(4000),
     attr_bvalue      RAW(2048),
     attr_value_len   INTEGER,
     attr_type        INTEGER ,
     attr_mod_op      INTEGER
);

GRANT EXECUTE ON LDAP_ATTR to public;

CREATE TYPE LDAP_ATTR_LIST AS TABLE OF LDAP_ATTR;
/
GRANT EXECUTE ON LDAP_ATTR_LIST to public;

---------------------------------------------------------------------------------------------------
-- Name: LDAP_EVENT
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains event information plus the attribute
--              list.
---------------------------------------------------------------------------------------------------

CREATE TYPE LDAP_EVENT AS OBJECT (
          event_type  VARCHAR2(32),
          event_id    VARCHAR2(32),
          event_src   VARCHAR2(1024),
          event_time  VARCHAR2(32),
          object_name VARCHAR2(1024),
          object_type VARCHAR2(32),
          object_guid VARCHAR2(32),
          object_dn   VARCHAR2(1024),
          profile_id  VARCHAR2(1024),
          attr_list   LDAP_ATTR_LIST ) ;
/

GRANT EXECUTE ON LDAP_EVENT to public;

---------------------------------------------------------------------------------------------------
-- Name: LDAP_EVENT_STATUS
-- Data Type: OBJECT
-- DESCRIPTION: This structure contains information that is sent by the
--              consumer of an event to the supplier in response to the
--              actual event.
 ---------------------------------------------------------------------------------------------------

CREATE TYPE LDAP_EVENT_STATUS AS OBJECT (
          event_id          VARCHAR2(32),
          orclguid          VARCHAR(32),
          error_code        INTEGER,
          error_String      VARCHAR2(1024),
          error_disposition VARCHAR2(32)) ;
/

GRANT EXECUTE ON LDAP_EVENT_STATUS to public;

13.6 Provisioning Event Interface (Version 1.1)

You must develop logic to consume events generated by the provisioning integration service. The interface between the application and the provisioning integration service can be table-based, or it can use PL/SQL callbacks.

The PL/SQL callback interface requires that you develop a PL/SQL package that the provisioning integration service invokes in the application-specific database. Choose any name for the package, but be sure to use the same name when you register the package at subscription time. Implement the package using the following PL/SQL package specification:

Rem
Rem      NAME
Rem         ldap_ntfy.pks - Provisioning Notification Package Specification.
Rem

DROP TYPE LDAP_ATTR_LIST;
DROP TYPE LDAP_ATTR;

-- LDAP ATTR
----------------------------------------------------------------
--
--  Name        : LDAP_ATTR
--  Data Type   : OBJECT
--  DESCRIPTION : This structure contains details regarding 
--                an attribute. 
--
----------------------------------------------------------------
CREATE TYPE LDAP_ATTR AS OBJECT (                                
     attr_name        VARCHAR2(255),
     attr_value       VARCHAR2(2048),
     attr_bvalue      RAW(2048),
     attr_value_len   INTEGER,
     attr_type        INTEGER  -- (0 - String, 1 - Binary)
     attr_mod_op      INTEGER
);
/
 GRANT EXECUTE ON LDAP_ATTR to public;

-------------------------------------------------------------
--
--  Name        : LDAP_ATTR_LIST
--  Data Type   : COLLECTION
--  DESCRIPTION : This structure contains collection 
--                of attributes.
--
-------------------------------------------------------------
CREATE TYPE LDAP_ATTR_LIST AS TABLE OF LDAP_ATTR;
/
 GRANT EXECUTE ON LDAP_ATTR_LIST to public;

-------------------------------------------------------------------------------
--
--  NAME        : LDAP_NTFY
--  DESCRIPTION : This is a notifier interface implemented by Provisioning System
--                clients to receive information about changes in Oracle Internet
--                Directory. The name of package can be customized as needed.
--                The function names within this package should not be changed.
--
--
-------------------------------------------------------------------------------
CREATE OR REPLACE PACKAGE LDAP_NTFY AS

--
-- LDAP_NTFY data type definitions
--


-- Event Types
USER_DELETE               CONSTANT VARCHAR2(256) := 'USER_DELETE';
USER_MODIFY               CONSTANT VARCHAR2(256) := 'USER_MODIFY';
GROUP_DELETE              CONSTANT VARCHAR2(256) := 'GROUP_DELETE';
GROUP_MODIFY              CONSTANT VARCHAR2(256) := 'GROUP_MODIFY';

-- Return Codes (Boolean)
SUCCESS                   CONSTANT NUMBER  := 1;
FAILURE                   CONSTANT NUMBER  := 0;

-- Values for attr_mod_op in LDAP_ATTR object.
MOD_ADD                   CONSTANT NUMBER  := 0;
MOD_DELETE                CONSTANT NUMBER  := 1;
MOD_REPLACE               CONSTANT NUMBER  := 2;
---------------------------------------------------------------------------------------------------
-- Name: LDAP_NTFY
-- DESCRIPTION: This is the interface to be implemented by Provisioning System
--              clients to send information to and receive information from
--              Oracle Internet Directory. The name of the package can be 
--              customized as needed. The function names within this package 
--              should not be changed.
 ---------------------------------------------------------------------------------------------------

CREATE OR REPLACE PACKAGE LDAP_NTFY AS

13.6.5 Callbacks

A callback is a function invoked by the provisioning integration service to send or receive notification events. While transferring events for an object, the related attributes can also be sent along with other details. The attributes are delivered as a collection (array) of attribute containers, which are in unnormalized form: if an attribute has two values, two rows are sent in the collection.

13.6.5.1 GetAppEvent()

The Oracle Directory Integration and Provisioning server invokes this API in the remote database. It is up to the application to respond with an event. The Oracle Directory Integration and Provisioning processes the event and sends the status back using the PutAppEventStatus() callback. The return value of GetAppEvent() indicates whether an event is returned or not.

FUNCTION GetAppEvent (event OUT LDAP_EVENT)
RETURN NUMBER;

-- Return CONSTANTS
EVENT_FOUND          CONSTANT NUMBER  := 0;
EVENT_NOT_FOUND      CONSTANT NUMBER  := 1403;

If the provisioning server is not able to process the event—that is, it runs into some type of LDAP error—it responds with EVENT_RESEND. The application is expected to resend that event when GetAppEvent() is invoked again.

If the provisioning server is able to process the event, but finds that the event cannot be processed—for example, the user to be modified does not exist, or the user to be subscribed does not exist, or the user to be deleted does not exist—then it responds with EVENT_ERROR to indicate to the application that something was wrong. Resending the event is not required. It is up to the application to handle the event.

Note the difference between EVENT_RESEND and EVENT_ERROR in the previous discussion. EVENT_RESEND means that it was possible to apply the event but the server could not. If it gets the event again, it might succeed.

EVENT_ERROR means there is no error in performing directory operations, but the event could not be processed due to other reasons.

PK.6,PKؐj?OEBPS/java_ext.htmh! Using the Java API Extensions to JNDI

5 Using the Java API Extensions to JNDI

This chapter explains how to use Java extensions to the standard directory APIs to perform many of the operations introduced in Chapter 3. The chapter presents use cases. The Oracle extensions to the standard APIs are documented in full in Oracle Fusion Middleware Java API Reference for Oracle Internet Directory.

The chapter contains the following topics:

5.1 Sample Code

Sample code is available at this URL:

http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications–Oracle Application Server.

5.2 Installing the Java Extensions

The Java extensions are installed along with the standard Java APIs when the LDAP client is installed. The APIs and their extensions are found at $ORACLE_HOME/jlib/ldapjclnt10.jar.

5.3 Using the oracle.ldap.util Package to Model LDAP Objects

In Java, LDAP entities—users, groups, realms, and applications—are modeled as Java objects instead of as handles. This modeling is done in the oracle.java.util package. All other utility functionality is modeled either as individual objects—as, for example, GUID—or as static member functions of a utility class.

For example, to authenticate a user, an application must follow these steps:

  1. Create oracle.ldap.util.User object, given the user DN.

  2. Create a DirContext JNDI object with all of the required properties, or get one from a pool of DirContext objects.

  3. Invoke the User.authenticateUser method, passing in a reference to the DirContext object and the user credentials.

  4. If the DirContext object was retrieved from a pool of existing DirContext objects, return it to that pool.

Unlike their C and PL/SQL counterparts, Java programmers do not have to explicitly free objects. The Java garbage collection mechanism performs this task.

5.4 The Classes PropertySetCollection, PropertySet, and Property

Many of the methods in the user, subscriber, and group classes return a PropertySetCollection object. The object represents a collection of one or more LDAP entries. Each of these entries is represented by a PropertySet object, identified by a DN. A property set can contain attributes, each represented as a property. A property is a collection of one or more values for the particular attribute it represents. An example of the use of these classes follows:

PropertySetCollection psc = Util.getGroupMembership( ctx,
                                                     myuser,
                                                     null,
                                                     true );
    // for loop to go through each PropertySet
    for (int i = 0; i < psc.size(); i++ ) {

    PropertySet ps = psc.getPropertySet(i);

   // Print the DN of each PropertySet
   System.out.println("dn:  " + ps .getDN());

   // Get the values for the "objectclass" Property
   Property objectclass = ps.getProperty( "objectclass" );

  
   // for loop to go through each value of Property "objectclass"
   for (int j = 0; j< objectclass.size(); j++) {

       // Print each "objectclass" value
       System.out.println("objectclass:  " + objectclass.getValue(j));
   }
}

The entity myuser is a user object. The psc object contains all the nested groups that myuser belongs to. The code loops through the resulting entries and prints out all the object class values of each entry.

5.5 Managing Users

All user-related functionality is abstracted in a Java class called oracle.ldap.util.User. The process works like this:

  1. Construct a oracle.ldap.util.User object based on a DN, GUID, or simple name.

  2. Invoke User.authenticateUser(DirContext, int, Object) to authenticate the user if necessary.

  3. Invoke User.getProperties(DirContext) to get the attributes of the user entry.

  4. Invoke User.getExtendedProperties(DirContext, int, String[]) to get the extended properties of the user. int is either shared or application-specific. String[] is the object that represents the type of property desired. If String[] is null, all properties in a given category are retrieved.

  5. Invoke PropertySetCollection.getProperties(int) to get the metadata required to parse the properties returned in step 4.

  6. Parse the extended properties and continue with application-specific logic. This parsing is also performed by application-specific logic.

5.6 Authenticating Users

User authentication is a common LDAP operation that compares the credentials that a user provides at login with the user's credentials in the directory. Oracle Internet Directory supports the following:

  • Arbitrary attributes can be used during authentication

  • Appropriate password policy exceptions are returned by the authentication method. Note, however, that the password policy applies only to the userpassword attribute.

The following code fragment shows how the API is used to authenticate a user:

 // User user1 - is a valid User Object
        try
        {
                user1.authenticateUser(ctx,
                    User.CREDTYPE_PASSWD, "welcome");
 
                // or
                // user1.authenticateUser(ctx, <any
attribute>, <attribute value>);
        }
        catch (UtilException ue)
        {
                // Handle the password policy error
accordingly
                if (ue instanceof PasswordExpiredException)
                        // do something
                else if (ue instanceof GraceLoginException)
                        // do something
        }

5.7 Creating Users

The subscriber class uses the createUser() method to programmatically create users. The object classes required by a user entry are configurable through Oracle Delegated Administration Services. The createUser() method assumes that the client understands the requirement and supplies the values for the mandatory attributes during user creation. If the programmer does not supply the required information the server returns an error.

The following snippet of sample code demonstrates the usage.

// Subscriber sub is a valid Subscriber object
// DirContext ctx is a valid DirContext
 
// Create ModPropertySet object to define all the attributes and their values.
ModPropertySet mps = new ModPropertySet();
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"cn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"sn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"mail",
"Anika@example.com");
 
// Create user by specifying the nickname and the ModPropertySet just defined
User newUser = sub.createUser( ctx, mps, true);
 
// Print the newly created user DN
System.out.println( newUser.getDN(ctx) );
 
// Perform other operations with this new user

5.8 Retrieving User Objects

The subscriber class offers the getUser() method to replace the public constructors of the User class. A user object is returned based on the specified information.

The following is a piece of sample code demonstrating the usage:

// DirContext ctx is contains a valid directory connection with
sufficient privilege to perform the operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the default
subscriber
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_DEFAULT, null, null);
 
// Obtain a User object representing the user whose
nickname is "Anika"
User user1 = sub.getUser(ctx, Util.IDTYPE_SIMPLE, "Anika",
null);
// Do work with this user
 
The getUser() method can retrieve users based on DN, GUID
and simple name.  A getUsers() method is also available to
perform a filtered search to return more than one user at a
time.  The returned object is an array of User objects.
For example,
 
// Obtain an array of User object where the user's nickname
starts with "Ani"
User[] userArr = sub.getUsers(ctx, Util.IDTYPE_SIMPLE,
"Ani", null);
// Do work with the User array

5.9 Retrieving Objects from Realms

This section describes how the Java API can be used to retrieve objects in identity management realms.

The RootOracleContext class represents the root Oracle Context. Much of the information needed for identity management realm creation is stored within the root Oracle Context. The RootOracleContext class offers the getSubscriber() method. It replaces the public constructors of the subscriber class and returns an identity management realm object based on the specified information.

The following is a piece of sample code demonstrating the usage:

// DirContext ctx contains a valid directory
// connection with sufficient privilege to perform the
// operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the
// Subscriber with simple name "Oracle"
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_SIMPLE, "Oracle", null);
 
// Do work with the Subscriber object

5.10 Example: Search for Oracle Single Sign-On Login Name

The following example shows how to find a user's login name when you have the simple name, GUID, or DN. The Oracle Single Sign-On login name is also referred to as nickname.

There are two parts to this example:

  1. Determine which attribute is used to store the nickname in this realm.

  2. Retrieve the User object and determine the value of the nickname attribute.

import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.io.*; 
 
public class NickNameSearch {
 
   public static void main(String[] args)
      throws Exception
   {
      InitialLdapContext ctx = ConnectionUtil.getDefaultDirCtx( args[0],
                                     args[1], args[2],args[3]);
 
      RootOracleContext roc=new RootOracleContext(ctx);
      Subscriber sub = null;
      sub = roc.getSubscriber(ctx, Util.IDTYPE_DEFAULT, null, null) ;
 
      PropertySetCollection psc = sub.getProperties(ctx, 
                                     Subscriber.USER_NAMING_PROPERTIES, null);
    
      String nickNameAttribute = null;
      try
      {
          nickNameAttribute = (String) psc.getPropertySet(0).getProperty(Subscriber.USER_NAMING_ATTR_SIMPLE).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute name
         System.exit(0);
      }
      System.out.println("Nickname attribute: " + nickNameAttribute);      
 
      // Retrieve user using simple name, guid or DN
      User user = sub.getUser(ctx, Util.IDTYPE_SIMPLE,"orcladmin", null);
      System.out.println("user DN: " + user.getDN(ctx));
 
      // Retrieve nickname value using User object
      psc = user.getProperties(ctx, new String[]{ nickNameAttribute });
     
      String nickName = null;
      try
      {
          nickName = (String) psc.getPropertySet(0).getProperty(nickNameAttribute).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute value 
         System.exit(0);
      }
      System.out.println("Nickname : " + nickName);      
   }
}

5.11 Discovering a Directory Server

A new Java class, the public class, has been introduced:

public class oracle.ldap.util.discovery.DiscoveryHelper

This class provides a method for discovering specific information from the specified source.

Two new methods are added to the existing Java class oracle.ldap.util.jndi.ConnectionUtil:

  • getDefaultDirCtx: This overloaded function determines the host name and port information of non-SSL ldap servers by making an internal call to oracle.ldap.util.discovery.DiscoveryHelper.discover().

  • getSSLDirCtx: This overloaded function determines the host name and port information of SSL ldap servers by making an internal call to oracle.ldap.util.discovery.DiscoveryHelper.discover().

5.12 Example: Discovering a Directory Server

The following is a sample Java program for directory server discovery:

import java.util.*;
import java.lang.*;
import oracle.ldap.util.discovery.*;
import oracle.ldap.util.jndi.*;
 
public class dsdtest
{
  public static void main(String s[]) throws Exception
  {
    HashMap reshdl = new HashMap();
    String result = new String();
    Object resultObj = new Object();
    DiscoveryHelper disco = new
DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);
 
// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com")
;
 
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD,
   DiscoveryHelper.USE_INPUT_DN_METHOD);
 
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");
 
// Call the discover method
int res=disco.discover(reshdl);
if (res!=0)
   System.out.println("Error Code returned by the discover method is :"+res) ;
 
// Print the results
printReshdl(reshdl);
}
 
public static void printReshdl(HashMap reshdl)
{
  ArrayList result = (ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
 
if (result != null)
{
  if (result.size() == 0) return;
  System.out.println("The hostnames are :-");
  for (int i = 0; i< result.size();i++)
  {
      String host = (String)result.get(i);
      System.out.println((i+1)+".
'"+host+"'");
   }
  }
 }
}

5.13 Using DIGEST-MD5 to Perform SASL Authentication

When using JNDI to create a SASL connection, you must set these javax.naming.Context properties:

  • Context.SECURITY_AUTHENTICATION = "DIGEST-MD5"

  • Context.SECURITY_PRINCIPAL

The latter sets the principal name. This name is a server-specific format. It can be either of the following:

  • The DN—that is, dn:—followed by the fully qualified DN of the entity being authenticated

  • The string u: followed by the user identifier.

    The Oracle directory server accepts just a fully qualified DN such as cn=user,ou=my department,o=my company.


Note:

The SASL DN must be normalized before it is passed to the API that calls the SASL bind. To generate SASL verifiers, Oracle Internet Directory supports only normalized DNs.

5.14 Example: Using SASL Digest-MD5 auth-int and auth-conf Modes

The following code provides an example of Java LDAP/JNDI using SASL Digest-MD5.

/* $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $ */
 
/* Copyright (c) 2003, 2005, Oracle. All rights reserved.  */
 
/*
  DESCRIPTION
   <short description of component this file declares/defines>
 
  PRIVATE CLASSES
   <list of private classes defined - with one-line descriptions>
 
  NOTES
   <other useful comments, qualifications, and so on.>
 
  MODIFIED    (MM/DD/YY)
   qdinh       04/23/03 - Creation
*/
 
/**
*  @version $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $
*  @author  qdinh   *  @since   release specific (what release of product did this appear in)
*/
 
package oracle.ldap.util.jndi;
 
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.lang.*;
import java.util.*;  
public class LdapSasl
{
   public static void main( String[] args)
       throws Exception
   {
 
    int numofargs;
 
    numofargs = args.length;
 
    Hashtable hashtable = new Hashtable();
 
    // Look through System Properties for Context Factory if it is available
    // then set the CONTEXT factory only if it has not been set
    // in the environment -
    // set default to com.sun.jndi.ldap.LdapCtxFactory
 
    hashtable.put(Context.INITIAL_CONTEXT_FACTORY,
          "com.sun.jndi.ldap.LdapCtxFactory");
    // possible valid arguments
    // args[0] - hostname
    // args[1] - port number
    // args[2] - Entry DN
    // args[3] - Entry Password
    // args[4] - QoP [ auth | auth-int | auth-conf ]
    // args[5] - SASL Realm
    // args[6] - Cipher Choice
    //    If QoP == "auth-conf" then args[6] cipher choice can be
    //     - des
    //     - 3des
    //     - rc4
    //     - rc4-56
    //     - rc4-40
 
    hashtable.put(Context.PROVIDER_URL, "ldap://"+args[0]+":"+args[1]);
        hashtable.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
    System.out.println("hash put security dn: " + args[2]);
    hashtable.put(Context.SECURITY_PRINCIPAL, args[2] );
    hashtable.put(Context.SECURITY_CREDENTIALS, args[3] );
 
    // For Quality of Protection modes
    // 1. Authentication and Data Integrity Mode - "auth-int"
    // 2. Authentication and Data Confidentiality Mode  "auth-conf"
 
    //
    // hashtable.put("javax.security.sasl.qop",args[4]);
    hashtable.put("javax.naming.security.sasl.realm", args[5]);
   
    // Setup Quality of Protection
    //
    // System.out.println("hash sasl.qop: " + args[4]);
 
    hashtable.put("javax.security.sasl.qop",args[4]);
 
   
    if (numofargs > 4)
    {
    if (args[4].equalsIgnoreCase("AUTH-CONF"))
    {
 
        //  Setup a cipher choice only if QoP == "auth-conf"
        String strength = "high";
        String cipher = new String(args[6]);
                if (cipher.compareToIgnoreCase("rc4-40") == 0)
        strength = "low";
        else if (cipher.compareToIgnoreCase("rc4-56") == 0 ||
             cipher.compareToIgnoreCase("des")== 0 )
        strength = "medium";
        else if (cipher.compareToIgnoreCase("3des") == 0 ||
             cipher.compareToIgnoreCase("rc4") == 0)
        strength = "high";
 
        // setup cipher choice
        System.out.println("hash sasl.strength:"+strength);
        hashtable.put("javax.security.sasl.strength",strength);
    }
 
    // set maxbuffer length if necessary
    if (numofargs > 7 && !"".equals(args[6]))
        hashtable.put("javax.security.sasl.maxbuf", args[5].toString());
    }
 
 
    // Enable Debug --
    // hashtable.put("com.sun.jndi.ldap.trace.ber", System.err);
 
    LdapContext ctx = new InitialLdapContext(hashtable,null);
 
 
    // At this stage - SASL Digest -MD5 has been successfully
 
    System.out.println("sasl bind successful");
 
    // Ldap Search Scope Options
    //
    // - Search base - OBJECT_SCOPE
    // - One Level   - ONELEVEL_SCOPE
    // - Sub Tree    - SUBTREE_SCOPE
    //
        // Doing an LDAP Search
    PropertySetCollection psc = Util.ldapSearch(ctx,"o=oracle,dc=com","objectclass=*",SearchControls.OBJECT_SCOPE,
                           new String[] {"*"});
      // Print out the serach result
    Util.printResults(psc);
 
    System.exit(0);
 
 }                                                              }
PKھhhPKؐj?OEBPS/ext_ldap.htm Extensions to the LDAP Protocol

3 Extensions to the LDAP Protocol

This chapter describes extensions to the LDAP protocol that are available in Oracle Internet Directory 11g Release 1 (11.1.1).

This chapter contains these topics:

3.1 SASL Authentication

Oracle Internet Directory supports two mechanisms for SASL-based authentication. This section describes the two methods. It contains these topics:

  • SASL Authentication by Using the DIGEST-MD5 Mechanism

  • SASL Authentication by Using External Mechanism

3.1.1 SASL Authentication by Using DIGEST-MD5

SASL Digest-MD5 authentication is the required authentication mechanism for LDAP Version 3 servers (RFC 2829). LDAP Version 2 does not support Digest-MD5.

To use the Digest-MD5 authentication mechanism, you can use either the Java API or the C API to set up the authentication. The C API supports only auth mode.

The SASL Digest-MD5 mechanism includes three modes, each representing a different security level or "Quality of Protection." They are:

  • auth—Authentication only. Authentication is required only for the initial bind. After that, information is passed in clear text.

  • auth-int—Authentication plus integrity. Authentication is required for the initial bind. After that, check sums are used to guarantee the integrity of the data.

  • auth-conf—Authentication plus confidentiality. Authentication is required for the initial bind. After that, encryption is used to protect the data. Five cipher choices are available:

    • DES

    • 3DES

    • RC4

    • RC4-56

    • RC4-40

These are all symmetric encryption algorithms.

Prior to 10g (10.1.4.0.1), Oracle Internet Directory supported only the auth mode of the Digest-MD5 mechanism. As of 10g (10.1.4.0.1), Oracle Internet Directory supports all three modes with the Java Naming and Directory Interface (JNDI) of jdk1.4 API or with the OpenLDAP Java API. The Oracle LDAP SDK supports only auth mode.

Out of the box, Oracle Internet Directory SASL Digest-MD5 authentication supports generation of static SASL Digest-MD5 verifiers based on user or password, but not based on realm. If you want to use SASL Digest-MD5 with realms, you must enable reversible password generation by changing the value of the orclpasswordencryptionenable attribute to 1 in the related password policy before provisioning new users. The LDIF file for modifying the value should look like this:

dn: cn=default,cn=pwdPolicies,cn=Common,cn=Products,cn=OracleContext
changetype: modify
replace: orclpwdencryptionenable
orclpwdencryptionenable: 1
 

The Digest-MD5 mechanism is described in RFC 2831 of the Internet Engineering Task Force. It is based on the HTTP Digest Authentication (RFC 2617).


See Also:


3.2 Using Controls

The LDAPv3 Protocol, as defined by RFC 2251, allows extensions by means of controls. Oracle Internet Directory supports several controls. Some are standard and described by RFCs. Other controls, such as the CONNECT_BY control for hierarchical searches are Oracle-specific. You can use controls with either Java or C.

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.

For information about using LDAP controls in C, see "Working With Controls".

For information about using LDAP controls in Java, see the documentation for the JNDI package javax.naming.ldap at http://java.sun.com/products/jndi.

The controls supported by Oracle Internet Directory 11g Release 1 (11.1.1) are listed in Table 3-1, "Request Controls Supported by Oracle Internet Directory" and Table 3-2, "Response Controls Supported by Oracle Internet Directory"

Table 3-1 Request Controls Supported by Oracle Internet Directory

Object IdentifierNameDescription

1.2.840.113556.1.4.319

OID_SEARCH_PAGING_CONTROL

See "Paged LDAP Search Results".

1.2.840.113556.1.4.473

OID_SEARCH_SORTING_REQUEST_CONTROL

See "Sorted LDAP Search Results".

2.16.840.1.113730.3.4.2

GSL_MANAGE_DSA_CONTROL

Used to manage referrals, dynamic groups, and alias objects in Oracle Internet Directory. For more information, please see RFC 3296, "Named Subordinate References in Lightweight Directory Access Protocol (LDAP) Directories," at http://www.ietf.org.

2.16.840.1.113894.1.8.1

OID_RESET_PROXYCONTROL_IDENTITY

Used to perform a proxy switch of an identity on an established LDAP connection. For example, suppose that Application A connects to the directory server and then wishes to switch to Application B. It can simply do a rebind by supplying the credentials of Application B. However, there are times when the proxy mechanism for the application to switch identities could be used even when the credentials are not available. With this control, Application A can switch to Application B provided Application A has the privilege in Oracle Internet Directory to proxy as Application B.

2.16.840.1.113894.1.8.2

OID_APPLYUSEPASSWORD_POLICY

Sent by applications that require Oracle Internet Directory to check for account lockout before sending the verifiers of the user to the application. If Oracle Internet Directory detects this control in the verifier search request and the user account is locked, then Oracle Internet Directory does not send the verifiers to the application. It sends an appropriate password policy error.

2.16.840.1.113894.1.8.3

CONNECT_BY

See "Performing Hierarchical Searches"

2.16.840.1.113894.1.8.4

OID_CLIENT_IP_ADDRESS

Intended for a client to send the end user IP address if IP lockout is to be enforced by Oracle Internet Directory.

2.16.840.1.113894.1.8.5

GSL_REQDATTR_CONTROL

Used with dynamic groups. Directs the directory server to read the specific attributes of the members rather than the membership lists.

2.16.840.1.113894.1.8.6

PasswordStatusRequestControl

When packaged as part of the LDAP Bind/Compare operation request, this control causes the server to generate a password policy response control. The actual response control depends on the situation. Cases include imminent password expiration, number of grace logins remaining, password expired, and account locked.

2.16.840.1.113894.1.8.14

OID_DYNAMIC_VERIFIER_REQUEST_CONTROL

The request control that the client sends when it wants the server to create a dynamic password verifier. The server uses the parameters in the request control to construct the verifier.

2.16.840.1.113894.1.8.16

AccountStatusRequestControl

When packaged with the LDAP search operation associated with the authentication process, the Oracle Internet Directory returns a password policy response control to inform the client application of account state related information like account lockout, password expiration etc. The application can then parse and enforce the results.

2.16.840.1.113894.1.8.23

GSL_CERTIFICATE_CONTROL"

Certificate search control. The request control that the client sends to specify how to search for a user certificate. See the appendix "Searching the Directory for User Certificates" in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory.

2.16.840.1.113894.1.8.29

EffectivePolicyControl

This control is packaged as part of an LDAP base search, where the base DN is that of the user entry being tested. The entry need not exist in the directory at the time. Passing this control results in the return of the LDAP entry describing the applicable password policy, assuming the entity performing the search has the access rights to view the password policy entry. If the desired password is provided as the optional testPassword parameter, the directory server returns the response control 2.16.840.1.113894.1.8.32.

2.16.840.1.113894.1.8.36

DelSubtreeControl

When this control is sent with a delete operation, it causes the deletion of the entire subtree below the DN provided. Any user having necessary privileges can perform this operation.


Table 3-2 Response Controls Supported by Oracle Internet Directory

Object IdentifierNameDescription

2.16.840.1.113894.1.8.7

OID_PASSWORD_EXPWARNING_CONTROL

Password policy control. Response control that the server sends when the pwdExpireWarning attribute is enabled and the client sends the request control. The response control value contains the time in seconds to password expiration.

2.16.840.1.113894.1.8.8

OID_PASSWORD_GRACELOGIN_CONTROL

Password policy control. The response control that the server sends when grace logins are configured and the client sends a request control. The response control value contains the remaining number of grace logins.

2.16.840.1.113894.1.8.9

OID_PASSWORD_MUSTCHANGE_CONTROL

Password policy control. The response control that the server sends when forced password reset is enabled and the client sends the request control. The client must force the user to change the password upon receipt of this control.

2.16.840.1.113894.1.8.15

OID_DYNAMIC_VERIFIER_RESPONSE_CONTROL

The response control that the server sends to the client when an error occurs. The response control contains the error code.

2.16.840.1.113894.1.8.32

PasswordValidationControl

The server sends this in response to control 2.16.840.1.113894.1.8.29 when the desired password is provided as the optional testPassword parameter. A client application can parse the validationResult to determine whether the password can be accepted by the server ("Success") or the reason it has been rejected. The same type of error message generated during a failed LDAP modify operation on userpassword is returned as the value.


To find out what controls are available in your Oracle Internet Directory installation, type:

ldapsearch -p port -b "" -s base "objectclass=*"

Look for entries that begin with supportedcontrol=.

3.3 Proxying on Behalf of End Users

Often applications must perform operations that require impersonating an end user. An application may, for example, want to retrieve resource access descriptors for an end user. (Resource access descriptors are discussed in the concepts chapter of Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory.)

A proxy switch occurs at run time on the JNDI context. An LDAP v3 feature, proxying can only be performed using InitialLdapContext, a subclass of InitialDirContext. If you use the Oracle extension oracle.ldap.util.jndi.ConnectionUtil to establish a connection (the example following), InitialLdapContext is always returned. If you use JNDI to establish the connection, make sure that it returns InitialLdapContext.

To perform the proxy switch to an end user, the user DN must be available. To learn how to obtain the DN, see the sample implementation of the oracle.ldap.util.User class at this URL:

http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications—Fusion Middleware, then look for "Sample Application Demonstrating Proxy Switching using Oracle Internet Directory Java API."

This code shows how the proxy switch occurs:

import oracle.ldap.util.jndi.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import javax.naming.*;

public static void main(String args[])
{
  try{
       InitialLdapContext appCtx=ConnectionUtil.getDefaultDirCtx(args[0], // host
                                                                 args[1], // port
                                                                 args[2], // DN
                                                                 args[3]; // pass)
         // Do work as application
         // . . .
         String userDN=null;
         // assuming userDN has the end user DN value
         // Now switch to end user
         ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
         ctx.addToEnvironment("java.naming.security.credentials", "");
         Control ctls[] = {
           new ProxyControl()
         };
         ((LdapContext)ctx).reconnect(ctls);
         // Do work on behalf of end user
         // . . .
      }
    catch(NamingException ne)
      {
       // javax.naming.NamingException is thrown when an error occurs 
      }
}

The ProxyControl class in the code immediately preceding implements a javax.naming.ldap.Control. To learn more about LDAP controls, see the LDAP control section of Oracle Fusion Middleware Reference for Oracle Identity Management. Here is an example of what the ProxyControl class might look like:

import javax.naming.*;
import javax.naming.ldap.Control;
import java.lang.*;
 
public class ProxyControl implements Control {
 
   public byte[] getEncodedValue() {
      return null;
   }
 
   public String getID() {
      return "2.16.840.1.113894.1.8.1";
   }
 
   public boolean isCritical() {
      return false;
   }
}

3.4 Creating Dynamic Password Verifiers

You can modify the LDAP authentication APIs to generate application passwords dynamically—that is, when users log in to an application. This feature has been designed to meet the needs of applications that provide parameters for password verifiers only at runtime.

This section contains the following topics:

3.4.3 Parameters Required by the Hashing Algorithms

Table 3-4 lists the four hashing algorithms that are used to create dynamic password verifiers. The table also lists the parameters that each algorithm uses as building blocks. Note that, although all algorithms use the user name and password parameters, they differ in their use of the realm and nonce parameters.

3.4.4 Configuring the Authentication APIs

Applications that require password verifiers to be generated dynamically must include DynamicVerifierRequestControl in their authentication APIs. Either ldap_search or ldap_compare must incorporate the controlOID and the control values as parameters. They must BER-encode the control values as shown in "Syntax for DynamicVerifierRequestControl"; then they must send both controlOID and the control values to the directory server.

3.5 Performing Hierarchical Searches

One of the server controls you can pass to an LDAP search function is CONNECT_BY. This is an Oracle-specific control that causes the search to traverse a hierarchy. For example, if you search for all the users in group1, without the CONNECT_BY control, the search function returns only users who are direct members of group1. If you pass the CONNECT_BY control, however, the search function traverses the hierarchy. If group2 is a member of group1, the search also returns users in group2. If group3 is a member of group2, the search also returns users in group3, and so forth.

3.5.2 Value Fields in the CONNECT_BY Control

In previous releases, the CONNECT_BY control required no values. Because of the new functionality, you can now pass one or both of the following values to CONNECT_BY:

  • Hierarchy-establishing attribute–A string representing the attribute to be searched. This value is necessary only when searching through all containers in which an entry is contained. When searching through containers contained within an entry, you need not provide this value because the search filter provides that information.

  • Number of levels–An integer representing the number of levels to traverse. If the value is 0, the search traverses all levels. The default value is 0, so you need not pass this value if you want the search to traverse all leve.s

Example 1: Find All the Groups to Which a User Belongs

Using a filter such as (member=cn=jsmith), you do not need to provide the hierarchy-establishing attribute member because it is in the search filter. You do not need to pass a value for the number of levels because 0 is the default.

Example 2: Find Only the Groups to Which a User Directly Belongs

Using the same filter as in Example 1, you would pass the integer control value 1. The result would be the same as if you did not use the CONNECT_BY control at all.

Example 3: Find All Members of a Group

In this case, your search filter would specify (objectclass=*), but if you want to find all members of group1, the attribute for traversing the hierarchy is member. For this search, you must pass the string "member" as the hierarchy-establishing attribute. You do not need to pass a value for the number of levels because 0 is the default.

Example 4: Finding all Managers of a User

This is similar to Example 3, except that you want to find all managers of the user jsmith, so manager is the attribute for traversing the hierarchy. For this search, you would pass the string "manager". You do not need to pass a value for the number of levels because 0 is the default.

3.6 Sorted LDAP Search Results

As of Oracle Internet Directory 10g (10.1.4.0.1), you can obtain sorted results from an LDAP search, as described by IETF RFC 2891. You request sorted results by passing a control of type 1.2.840.113556.1.4.473 to the search function. The server returns a response control is of type 1.2.840.113556.1.4.474. Error processing and other details are described in RFC 2891.


See Also:

IETF RFC 2891, "LDAP Control Extension for Server Side Sorting of Search Results," at http://www.ietf.org.

Sorting and paging may be used together.

The Oracle Internet Directory implementation of RFC 2891 has the following limitations:

  • It supports only one attributeType in the control value.

  • It uses the default ordering rule defined in the schema for each attribute.

  • Linguistic sorting is not supported.

  • The default sorting order is ascending.

  • If a sort key is a multi-valued attribute, and an entry has multiple values for that attriute, and there are no other controls that affect the sorting order, then the server uses the least value, according to the ordering rule for that attribute.

  • The sort attribute must be searchable. That is, it must be a cataloged attribute in Oracle Internet Directory.

3.7 Paged LDAP Search Results

As of Oracle Internet Directory 10g (10.1.4.0.1), you can obtain paged results from an LDAP search, as described by IETF RFC 2696. You request sorted results by passing a control of type 1.2.840.113556.1.4.319 to the search function. Details are described in RFC 2696.


See Also:

IETF RFC 2696, "LDAP Control Extension for Simple Paged Results Manipulation," at http://www.ietf.org.

Sorting and paging may be used together.

The Oracle Internet Directory implementation of RFC 2696 has the following limitations:

  • The number of entries in a page might be less than the page size if an ACI partially blocks some entries from the search results.

  • The paging response control does not contain the total entry count estimation. The return value is always 0.

3.8 Password Policies

The Oracle Internet Directory natively supports a rich set of policies governing passwords. See "Managing Password Policies" in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory. You should design your applications to interact with the directory's password policies at runtime and handle any resulting events gracefully. Oracle Internet Directory provides several mechanisms to allow clients to interact with the server's password policies.

This section contains the following topics:

3.8.1 User Provisioning

If your application provisions its own users in the directory, you should test passwords for acceptability by the server before committing the new user entry into the directory. You can test a password by using the following custom control:

EffectivePolicyControl
::= SEQUENCE {
                        controlType     2.16.840.1.113894.1.8.29,
                        criticality     BOOLEAN DEFAULT FALSE,
                        controlValue    testPassword
                       }
testPassword ::= OCTET STRING (optional)

Package this control as part of an LDAP base search, where the base DN is that of the user entry being tested. The entry does not need to exist in the directory at the time. The server returns the LDAP entry describing the applicable password policy, assuming the entity performing the search has the access rights to view the password policy entry. Providing the desired password as the optional testPassword parameter results in the directory server returning the following response control:

PasswordValidationControl
::= SEQUENCE {
                        controlType     2.16.840.1.113894.1.8.32,
                        criticality     BOOLEAN DEFAULT FALSE,
                        controlValue    validationResult
                       }
validationResult ::= OCTET STRING

Your client application can parse the validationResult to determine whether the password is accepted by the server ("Success") or the reason it has been rejected. The error message is the same as that generated during a failed LDAP modify operation on userpassword.

3.8.2 User Authentication

User authentication use-cases broadly fall into two main categories:

  1. LDAP Bind/Compare Operation-Based Authentication

  2. LDAP Search Operation-Based Authentication

The former refers to authentication performed on the standard userpassword attribute. The entire authentication process is performed within the directory server, and appropriate internal events are generated to update various account states as necessary.

The latter refers to authentication performed against other authentication tokens, such as password verifiers, maintained as part of a user entry. The token may be retrieved by the application. The authentication process occurs within the application and outside the scope of the directory server. Therefore in LDAP search-based authentications, the directory does not implicitly know the result of the authentication attempt.

The following two subsections describe the best practices for application integration when dealing with these two types of authentication scenarios.

3.8.2.2 LDAP Search Operation-Based Authentication

If an application performs its own authentication after retrieving an authentication token from the directory, then none of the state-related policies are effective. Without these policies, scenarios such as locked accounts aren't enforceable, and users with expired accounts can still authenticate against the application.

The Oracle Internet Directory provides two mechanism that allow such an application to leverage the state related policy framework already present in the directory server:

3.8.2.2.2 Ability to Inform the Directory of Authentication Success/Failure

Oracle Internet Directory provides this ability through the virtual attribute: orclAccountStatusEvent.

This attribute is available on all user entries as a virtual attribute. That is, it has no disk footprint. However, modify operations can be applied on it. By default, a directory ships with restricted access to this attribute, so you must ask the directory administrator to grant your application identity write access on the attribute for the relevant user population.

You communicate authentication success or failure to the directory by modifying this attribute to hold UserAccountEvent. The following LDIF illustrates this.

dn: UserDN
changetype: modify
replace: orclAccountStatusEvent
orclAccountStatusEvent: UserAccountEvent

The Oracle Internet Directory understands the following values for UserAccountEvent:

UserAccountEvent = 1 (Authentication Success)
UserAccountEvent = 2 (Authentication Failure)

Upon receipt of these events, the Oracle Internet Directory invokes the same logic that is invoked during an authentication/success failure of an LDAP bind or compare operation, thereby updating the necessary account states.

In this way, you can leverage the existing account state related infrastructure available in the Oracle Internet Directory to secure your application.

3.8.3 User Account Maintenance

User account maintenance and its interaction with password policies occur mostly around periodic password modifications. We recommend that applications utilize the EffectivePolicyControl described above to retrieve the effective policy and parse it to generate a message guiding the end user to the password construction requirements. Furthermore, we encourage the usage of the "test" capabilities encapsulated in this control to direct the end user towards the cause behind a modification failure. Handling these situations within the application reduces administrative overhead.

Secondly, there are a multitude of use-cases requiring a user to change his or her password upon next logon. The Oracle Internet Directory natively triggers this requirement when the pwdmustchange password policy element is enabled and a userpassword undergoes a non-self modification. However, in the event that an explicit trigger of this requirement is needed, the Oracle Internet Directory supports it also via the orclAccountStatusEvent attribute described above. The relevant events are:

UserAccountEvent = 3 (Require Password Reset on next Logon)
UserAccountEvent = 4 (Clear Password Reset Requirement)

If the application has an administrative interface, this functionality may be desirable and can be exposed to the administrator.

PKAPKؐj?OEBPS/xmlsyn_c.htm'e DSML Syntax

B DSML Syntax

Directory Services Mark-up Language (DSML) is deprecated in Oracle Fusion Middleware 11g Release 1 (11.1.1) and might not be supported in future releases.

This appendix contains the following sections:

B.1 Capabilities of DSML

Directory services form a core part of distributed computing. XML is becoming the standard markup language for Internet applications. As directory services are brought to the Internet, there is a pressing and urgent need to express the directory information as XML data. This caters to the growing breed of applications that are not LDAP-aware yet require information exchange with a LDAP directory server.

Directory Services Mark-up Language (DSML) defines the XML representation of LDAP information and operations. The LDAP Data Interchange Format (LDIF) is used to convey directory information, or a set of changes to be applied to directory entries. The former is called Attribute Value Record and the latter is called Change Record.

B.2 Benefits of DSML

Using DSML with Oracle Internet Directory and Internet applications makes it easier to flexibly integrate data from disparate sources. Also, DSML enables applications that do not use LDAP to communicate with LDAP-based applications, easily operating on data generated by an Oracle Internet Directory client tool or accessing the directory through a firewall.

DSML is based on XML, which is optimized for delivery over the Web. Structured data in XML is uniform and independent of application or vendors, thus making possible numerous new flat file type synchronization connectors. After it is in XML format, the directory data can be made available in the middle tier and have more meaningful searches performed on it.

B.3 DSML Syntax

A DSML version 1 document describes either directory entries, a directory schema or both. Each directory entry has a unique name called a distinguished name (DN). A directory entry has several property-value pairs called directory attributes. Every directory entry is a member of several object classes. An entry's object classes constrain the directory attributes the entry can take. Such constraints are described in a directory schema, which may be included in the same DSML document or may be in a separate document.

The following subsections briefly explain the top-level structure of DSML and how to represent the directory and schema entries.

B.4 Tools Enabled for DSML

With the XML framework, you can now use non-ldap applications to access directory data. The XML framework broadly defines the access points and provides the following tools:

The client tool ldifwrite generates directory data and schema LDIF files. If you convert these LDIF files to XML, you can store the XML file on an application server and query it. The query and response time is small compared to performing an LDAP operation against an LDAP server.

PKrae''PKؐj?OEBPS/title.htm Oracle Fusion Middleware Application Developer's Guide for Oracle Identity Management, 11g Release 1 (11.1.1)

Oracle® Fusion Middleware

Application Developer's Guide for Oracle Identity Management

11g Release 1 (11.1.1)

E10186-02

January 2011


Oracle Fusion Middleware Application Developer's Guide for Oracle Identity Management, 11g Release 1 (11.1.1)

E10186-02

Copyright © 1999, 2011, Oracle and/or its affiliates. All rights reserved.

Primary Author:  Ellen Desmond

Contributors:  Vasuki Ashok , Ajay Keni, Ashish Kolli, Stephen Lee, Venkat Medam, Samit Roy, David Lin, Arun Theebaprakasam

This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.

The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.

If this software or related documentation is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, the following notice is applicable:

U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007). Oracle USA, Inc., 500 Oracle Parkway, Redwood City, CA 94065.

This software is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications which may create a risk of personal injury. If you use this software in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure the safe use of this software. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this software in dangerous applications.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

This software and documentation may provide access to or information on content, products, and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services.

Portions of this document are from "The C LDAP Application Program Interface," an Internet Draft of the Internet Engineering Task Force (Copyright (C) The Internet Society (1997-1999). All Rights Reserved), which expires on 8 April 2000. These portions are used in accordance with the following IETF directives: "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."

RSA
RSA and RC4 are trademarks of RSA Data Security. Portions of Oracle Internet Directory have been licensed by Oracle Corporation from RSA Data Security.

This product contains SSLPlus Integration SuiteTM version 1.2, from Consensus Development Corporation.

Sun Java System Directory Server and iPlanet are registered trademarks of Sun Microsystems, Inc.

PKa*PKؐj?OEBPS/preface.htm% Preface

Preface

Oracle Fusion Middleware Application Developer's Guide for Oracle Identity Management explains how to modify applications to work with Oracle Identity Management, including Oracle Application Server Single Sign-On, Oracle Internet Directory, Oracle Delegated Administration Services, and the Directory Integration Platform.

This preface contains these topics:

Audience

The following readers can benefit from this book:

Documentation Accessibility

Our goal is to make Oracle products, services, and supporting documentation accessible to all users, including users that are disabled. To that end, our documentation includes features that make information available to users of assistive technology. This documentation is available in HTML format, and contains markup to facilitate access by the disabled community. Accessibility standards will continue to evolve over time, and Oracle is actively engaged with other market-leading technology vendors to address technical obstacles so that our documentation can be accessible to all of our customers. For more information, visit the Oracle Accessibility Program Web site at http://www.oracle.com/accessibility/.

Accessibility of Code Examples in Documentation

Screen readers may not always correctly read the code examples in this document. The conventions for writing code require that closing braces should appear on an otherwise empty line; however, some screen readers may not always read a line of text that consists solely of a bracket or brace.

Accessibility of Links to External Web Sites in Documentation

This documentation may contain links to Web sites of other companies or organizations that Oracle does not own or control. Oracle neither evaluates nor makes any representations regarding the accessibility of these Web sites.

Access to Oracle Support

Oracle customers have access to electronic support through My Oracle Support. For information, visit http://www.oracle.com/support/contact.html or visit http://www.oracle.com/accessibility/support.html if you are hearing impaired.

Related Documents

For more information, see these Oracle resources:

If you are using Oracle Delegated Administration Services or Oracle Single Sign-On 10g (10.1.4.3.0) or later, please refer to the following documents in the Oracle Application Server 10g (10.1.4.0.1) library:

For additional information, see:

Conventions

The following text conventions are used in this document:

ConventionMeaning
boldfaceBoldface type indicates graphical user interface elements associated with an action, or terms defined in text or the glossary.
italicItalic type indicates book titles, emphasis, or placeholder variables for which you supply particular values.
monospaceMonospace type indicates commands within a paragraph, URLs, code in examples, text that appears on the screen, or text that you enter.

PKKB%%PKؐj?OEBPS/dbmsldap_ref.htm DBMS_LDAP PL/SQL Reference

9 DBMS_LDAP PL/SQL Reference

DBMS_LDAP contains the functions and procedures that enable PL/SQL programmers to access data from LDAP servers. This chapter examines all of the API functions in detail.

The chapter contains these topics:


Note:

Sample code for the DBMS_LDAP package is available at this URL:
http://www.oracle.com/technology/sample_code/

Look for the Oracle Identity Management link under Sample Applications—Fusion Middleware.


9.1 Summary of Subprograms

Table 9-1 DBMS_LDAP API Subprograms

Function or ProcedureDescription

FUNCTION init


init() initializes a session with an LDAP server. This actually establishes a connection with the LDAP server.

FUNCTION simple_bind_s


The function simple_bind_s() can be used to perform simple user name and password authentication to the directory server.

FUNCTION bind_s


The function bind_s() can be used to perform complex authentication to the directory server.

FUNCTION unbind_s


The function unbind_s() is used for closing an active LDAP session.

FUNCTION compare_s


The function compare_s() can be used to test if a particular attribute in a particular entry has a particular value.

FUNCTION search_s


The function search_s() performs a synchronous search in the LDAP server. It returns control to the PL/SQL environment only after all of the search results have been sent by the server or if the search request is 'timed-out by the server.

FUNCTION search_st


The function search_st() performs a synchronous search in the LDAP server with a client side time out. It returns control to the PL/SQL environment only after all of the search results have been sent by the server or if the search request is 'timed-out' by the client or the server.

FUNCTION first_entry


The function first_entry is used to retrieve the first entry in the result set returned by either search_s() or search_st.

FUNCTION next_entry


The function next_entry() is used to iterate to the next entry in the result set of a search operation.

FUNCTION count_entries


This function is used to count the number of entries in the result set. It can also be used to count the number of entries remaining during a traversal of the result set using a combination of the functions first_entry() and next_entry.

FUNCTION first_attribute


The function first_attribute() fetches the first attribute of a given entry in the result set.

FUNCTION next_attribute


The function next_attribute()fetches the next attribute of a given entry in the result set.

FUNCTION get_dn


The function get_dn() retrieves the X.500 distinguished name of a given entry in the result set.

FUNCTION get_values


The function get_values()can be used to retrieve all of the values associated with a given attribute in a given entry.

FUNCTION get_values_len


The function get_values_len() can be used to retrieve values of attributes that have a 'Binary' syntax.

FUNCTION delete_s


This function can be used to remove a leaf entry in the LDAP Directory Information Tree.

FUNCTION modrdn2_s


The function modrdn2_s() can be used to rename the relative distinguished name of an entry.

FUNCTION err2string


The function err2string() can be used to convert an LDAP error code to a string in the local language in which the API is operating.

FUNCTION create_mod_array


The function create_mod_array() allocates memory for array modification entries that are applied to an entry using the modify_s() functions.

PROCEDURE populate_mod_array (String Version)


Populates one set of attribute information for add or modify operations. This procedure call has to happen after DBMS_LDAP.create_mod_array() is called.

PROCEDURE populate_mod_array (Binary Version)


Populates one set of attribute information for add or modify operations. This procedure call has to occur after DBMS_LDAP.create_mod_array() is called.

PROCEDURE populate_mod_array (Binary Version. Uses BLOB Data Type)


Populates one set of attribute information for add or modify operations. This procedure call has to happen after DBMS_LDAP.create_mod_array() is called.

FUNCTION get_values_blob


The function get_values_blob() can be used to retrieve larger values of attributes that have a binary syntax.

FUNCTION count_values_blob


Counts the number of values returned by DBMS_LDAP.get_values_blob().

FUNCTION value_free_blob


Frees the memory associated with the BLOB_COLLECTION returned by DBMS_LDAP.get_values_blob().

FUNCTION modify_s


Performs a synchronous modification of an existing LDAP directory entry. Before calling add_s, you must call DBMS_LDAP.creat_mod_array() and DBMS_LDAP.populate_mod_array().

FUNCTION add_s


Adds a new entry to the LDAP directory synchronously. Before calling add_s, you must call DBMS_LDAP.creat_mod_array() and DBMS_LDAP.populate_mod_array().

PROCEDURE free_mod_array


Frees the memory allocated by DBMS_LDAP.create_mod_array().

FUNCTION count_values


Counts the number of values returned by DBMS_LDAP.get_values().

FUNCTION count_values_len


Counts the number of values returned by DBMS_LDAP.get_values_len ().

FUNCTION rename_s


Renames an LDAP entry synchronously.

FUNCTION explode_dn


Breaks a DN up into its components.

FUNCTION open_ssl


Establishes an SSL (Secure Sockets Layer) connection over an existing LDAP connection.

FUNCTION msgfree


This function frees the chain of messages associated with the message handle returned by synchronous search functions.

FUNCTION ber_free


This function frees the memory associated with a handle to BER_ELEMENT.

FUNCTION nls_convert_to_utf8


The nls_convert_to_utf8 function converts the input string containing database character set data to UTF-8 character set data and returns it.

FUNCTION nls_convert_from_utf8


The nls_convert_from_utf8 function converts the input string containing UTF-8 character set data to database character set data and returns it.

FUNCTION nls_get_dbcharset_name


The nls_get_dbcharset_name function returns a string containing the database character set name.



See Also:


9.2 Exception Summary

DBMS_LDAP can generate the exceptions described in Table 9-2.

Table 9-2 DBMS_LDAP Exception Summary

Exception NameOracle Error NumberCause of Exception
general_error

31202

Raised anytime an error is encountered that does not have a specific PL/SQL exception associated with it. The error string contains the description of the problem in the user's language.

init_failed

31203

Raised by DBMS_LDAP.init() if there are problems.

invalid_session

31204

Raised by all functions and procedures in the DBMS_LDAP package if they are passed an invalid session handle.

invalid_auth_method

31205

Raised by DBMS_LDAP.bind_s()if the authentication method requested is not supported.

invalid_search_scope

31206

Raised by all search functions if the scope of the search is invalid.

invalid_search_time_val
31207

Raised by DBMS_LDAP.search_st()if it is given an invalid value for a time limit.

invalid_message
31208

Raised by all functions that iterate through a result-set for getting entries from a search operation if the message handle given to them is invalid.

count_entry_error
31209

Raised by DBMS_LDAP.count_entries if it cannot count the entries in a given result set.

get_dn_error
31210

Raised by DBMS_LDAP.get_dn if the DN of the entry it is retrieving is NULL.

invalid_entry_dn
31211

Raised by all functions that modify, add, or rename an entry if they are presented with an invalid entry DN.

invalid_mod_array
31212

Raised by all functions that take a modification array as an argument if they are given an invalid modification array.

invalid_mod_option
31213

Raised by DBMS_LDAP.populate_mod_array if the modification option given is anything other than MOD_ADD, MOD_DELETE or MOD_REPLACE.

invalid_mod_type
31214

Raised by DBMS_LDAP.populate_mod_array if the attribute type that is being modified is NULL.

invalid_mod_value
31215

Raised by DBMS_LDAP.populate_mod_array if the modification value parameter for a given attribute is NULL.

invalid_rdn
31216

Raised by all functions and procedures that expect a valid RDN and are provided with an invalid one.

invalid_newparent
31217

Raised by DBMS_LDAP.rename_s if the new parent of an entry being renamed is NULL.

invalid_deleteoldrdn
31218

Raised by DBMS_LDAP.rename_s if the deleteoldrdn parameter is invalid.

invalid_notypes
31219

Raised by DBMS_LDAP.explode_dn if the notypes parameter is invalid.

invalid_ssl_wallet_loc
31220

Raised by DBMS_LDAP.open_ssl if the wallet location is NULL but the SSL authentication mode requires a valid wallet.

invalid_ssl_wallet_password
31221

Raised by DBMS_LDAP.open_ssl if the wallet password given is NULL.

invalid_ssl_auth_mode
31222

Raised by DBMS_LDAP.open_ssl if the SSL authentication mode is not 1, 2 or 3.


9.3 Data Type Summary

The DBMS_LDAP package uses the data types described in Table 9-3.

9.4 Subprograms

This section takes a closer look at each of the DBMS_LDAP subprograms.

9.4.1 FUNCTION init

init() initializes a session with an LDAP server. This actually establishes a connection with the LDAP server.

Syntax

FUNCTION init      
(
hostname IN VARCHAR2,
portnum  IN PLS_INTEGER
)
RETURN SESSION;

Parameters

Return Values

Exceptions

Usage Notes

DBMS_LDAP.init() is the first function that should be called because it establishes a session with the LDAP server. Function DBMS_LDAP.init() returns a session handle, a pointer to an opaque structure that must be passed to subsequent calls pertaining to the session. This routine returns NULL and raises the INIT_FAILED exception if the session cannot be initialized. After init() has been called, the connection has to be authenticated using DBMS_LDAP.bind_s or DBMS_LDAP.simple_bind_s().

See Also

DBMS_LDAP.simple_bind_s(), DBMS_LDAP.bind_s().

9.4.6 FUNCTION search_s

The function search_s performs a synchronous search in the directory. It returns control to the PL/SQL environment only after all of the search results have been sent by the server or if the search request is timed out by the server.

Syntax

FUNCTION search_s  
(
ld       IN  SESSION,
base     IN  VARCHAR2,
scope    IN  PLS_INTEGER,
filter   IN  VARCHAR2,
attrs    IN  STRING_COLLECTION,
attronly IN  PLS_INTEGER,
res      OUT MESSAGE
)
RETURN PLS_INTEGER;

Parameters

Return Values

Exceptions

Usage Notes

The function search_s() issues a search operation and does not return control to the user environment until all of the results have been returned from the server. Entries returned from the search, if any, are contained in the res parameter. This parameter is opaque to the caller. Entries, attributes, and values can be extracted by calling the parsing routines described in this chapter.

See Also

DBMS_LDAP.search_st(), DBMS_LDAP.first_entry(), DBMS_LDAP.next_entry.

9.4.7 FUNCTION search_st

The function search_st() performs a synchronous search in the LDAP server with a client-side time out. It returns control to the PL/SQL environment only after all of the search results have been sent by the server or if the search request is timed out by the client or the server.

Syntax

FUNCTION search_st  
(
ld       IN  SESSION,
base     IN  VARCHAR2,
scope    IN  PLS_INTEGER,
filter   IN  VARCHAR2,
attrs    IN  STRING_COLLECTION,
attronly IN  PLS_INTEGER,
tv       IN  TIMEVAL,
res      OUT MESSAGE
)
RETURN PLS_INTEGER;

Parameters

Return Values

Exceptions

Usage Notes

This function is very similar to DBMS_LDAP.search_s() except that it requires a time out value to be given.

See Also

DBMS_LDAP.search_s(), DBML_LDAP.first_entry(), DBMS_LDAP.next_entry.

9.4.11 FUNCTION first_attribute

The function first_attribute() fetches the first attribute of a given entry in the result set.

Syntax

FUNCTION first_attribute     
(
ld          IN  SESSION,
ldapentry   IN  MESSAGE,
ber_elem    OUT BER_ELEMENT
)
RETURN VARCHAR2;

Parameters

Return Values

Exceptions

Usage Notes

The handle to the BER_ELEMENT returned as a function parameter to first_attribute() should be used in the next call to next_attribute() to iterate through the various attributes of an entry. The name of the attribute returned from a call to first_attribute() can in turn be used in calls to the functions get_values() or get_values_len() to get the values of that particular attribute.

See Also

DBMS_LDAP.next_attribute(), DBMS_LDAP.get_values(), DBMS_LDAP.get_values_len(), DBMS_LDAP.first_entry(), DBMS_LDAP.next_entry().

9.4.14 FUNCTION get_values

The function get_values() can be used to retrieve all of the values associated with a given attribute in a given entry.

Syntax

FUNCTION get_values
(    
ld   IN SESSION,
ldapentry IN MESSAGE,
attr IN VARCHAR2
)
RETURN STRING_COLLECTION;

Parameters


Return Values

Exceptions

Usage Notes

The function get_values() can only be called after the handle to entry has been first retrieved by call to either first_entry() or next_entry(). The name of the attribute may be known beforehand or can be determined by a call to first_attribute() or next_attribute().The function get_values() always assumes that the data type of the attribute it is retrieving is a string. For retrieving binary data types, get_values_len() should be used.

See Also

DBMS_LDAP.first_entry(), DBMS_LDAP.next_entry(), DBMS_LDAP.count_values(), DBMS_LDAP.get_values_len().

9.4.17 FUNCTION modrdn2_s

The function modrdn2_s() can be used to rename the relative distinguished name of an entry.

Syntax

FUNCTION modrdn2_s 
(
ld IN SESSION,
entrydn in VARCHAR2
newrdn in VARCHAR2
deleteoldrdn IN PLS_INTEGER
)
RETURN PLS_INTEGER;

Parameters

Return Values

Exceptions

Usage Notes

The function nodrdn2_s() can be used to rename the leaf nodes of a DIT. It simply changes the relative distinguished name by which they are known. The use of this function is being deprecated in the LDAP v3 standard. Please use rename_s(), which fulfills the same purpose.

See Also

DBMS_LDAP.rename_s().