ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Directory Server Enterprise Edition開発者ガイド
11g リリース1 (11.1.1.7.0)
B72440-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

4 プラグインを使用したエントリの処理

この章では、ディレクトリ・エントリ、属性、属性値および識別名(DN)を処理するプラグインAPIの機能について説明します。また、エントリのLDAP Data Interchange Format (LDIF)文字列との変換、およびエントリがLDAPスキーマに準拠しているかどうかのチェックについても説明します。

この章で使用されているコードは、install-path/examples/entries.cのサンプル・プラグインとinstall-path/examples/dns.cのサンプル・プラグインで見つかります。

この章で使用されるプラグインAPI関数の詳細は、第15章「Directory Server関数リファレンス(パートI)」を参照してください。

この章の内容は、次のとおりです。

4.1 エントリの作成

この項では、ディレクトリでエントリを作成する方法について説明します。スペースを割り当てることによって新規エントリを作成し、完全に新しいエントリを作成します。または、既存エントリを複製し、その値を変更することによって新規エントリを作成します。

4.1.1 新規エントリの作成

次の例に示すように、slapi_entry_alloc()を使用して完全に新しいエントリを作成し、必要なメモリーを割り当てます。

例4-1 新規エントリの作成(entries.c)

#include "slapi-plugin.h"

int
test_ldif()
{
    Slapi_Entry * entry = NULL;        /* Entry to hold LDIF      */

    /* Allocate the Slapi_Entry structure.                        */
    entry = slapi_entry_alloc();

    /* Add code that fills the Slapi_Entry structure.             */

    /* Add code that uses the Slapi_Entry structure.              */

    /* Release memory allocated for the entry.                    */
    slapi_entry_free(entry);

    return (0);
}

4.1.2 エントリのコピーの作成

slapi_entry_dup()を使用して、エントリのコピーを作成します。

4.2 LDIF表現との変換

この項では、プラグインAPIを使用して、LDIFで表現されているエントリをSlapi_Entry構造体に変換する方法について説明します。また、Slapi_Entry構造体をLDIF文字列に変換する方法についても説明します。

LDIFファイルは、ディレクトリ・エントリに関する一連の判読可能な表現、およびオプションのアクセス制御命令として示されます。LDIFで表現されるエントリは、識別名の行で始まります。LDIF表現では、属性のオプションの行が続きます。構文を次の例に示します。

例4-2 エントリを表現するLDIF構文

dn:[:] dn-value\n
[attribute:[:] value\n]
[attribute:[:] value\n]
[single-space continued-value\n]*

二重コロン(::)は、がbase64でエンコードされていることを示します。Base64でエンコードされた値は、たとえば、属性値の途中で改行できます。

前述の例で示したように、後続の行の最初に空白を1つ残すことによって、LDIFの行を折りたたむことができます。

サンプルのLDIFファイルは、install-path/ldif/にあります。

LDIF構文の詳細は、『Oracle Directory Server Enterprise Editionリファレンス』の第4章「Directory ServerのLDIFおよび検索フィルタ」を参照してください。

4.2.1 LDIF文字列のSlapi_Entry構造体への変換

このタイプの変換は、slapi_str2entry()を使用することによって実現できます。この関数は、2つの引数として、変換する文字列と、slapi-plugin.hにおけるSLAPI_STR2ENTRY_*の形式のフラグを保持するintを取ります。関数は、次の例に示すように、成功の場合はSlapi_Entryへのポインタを戻し、それ以外はNULLを戻します。

例4-3 LDIF文字列との変換(entries.c)

#include "slapi-plugin.h"

#define LDIF_STR "dn: dc=example,dc=com\nobjectclass: \
    top\nobjectclass: domain\ndc: example\n"

int
test_ldif()
{
    char        * ldif  = NULL;        /* Example LDIF string     */
    Slapi_Entry * entry = NULL;        /* Entry to hold LDIF      */
    char        * str   = NULL;        /* String to hold entry    */
    int           len;                 /* Length of entry as LDIF */

    /* LDIF to Slapi_Entry                                        */
    entry = slapi_entry_alloc();
    ldif  = slapi_ch_strdup(LDIF_STR);
    entry = slapi_str2entry(ldif, SLAPI_STR2ENTRY_ADDRDNVALS);
    slapi_ch_free_string(&ldif);
    if (entry == NULL) return (-1);

    /* Slapi_Entry to LDIF                                        */
    str = slapi_entry2str(entry, &len);
    if (str == NULL) return (-1);
    slapi_log_info_ex(
        SLAPI_LOG_INFO_AREA_PLUGIN,
        SLAPI_LOG_INFO_LEVEL_DEFAULT,
        SLAPI_LOG_NO_MSGID,
        SLAPI_LOG_NO_CONNID,
        SLAPI_LOG_NO_OPID,
        "test_ldif in test-entries plug-in",
        "\nOriginal entry:\n%sEntry length: %d\n", str, len
    );

    slapi_entry_free(entry);

    return (0);
}

ここで、SLAPI_STR2ENTRY_ADDRDNVALSは、slapi_str2entry()のサポートされているフラグが一覧表示されたslapi-plugin.hで指定されたように、欠落した相対識別名(RDN)の値を追加します。

4.2.2 Slapi_Entry構造体のLDIF文字列への変換

このタイプの変換は、slapi_entry2str()を使用することによって実現できます。この関数は、2つの引数として、変換するエントリと、戻される文字列の長さを保持するintを取ります。関数は、例38-3に示すように、成功の場合はLDIFにchar *を戻し、それ以外はNULLを戻します。

4.3 エントリ属性および属性値の取得

この項では、エントリの実在属性に対して処理を繰り返し行う方法について説明します。この手法は、エントリに属する属性のリストを検索する場合に使用できます。エントリに特定の属性が含まれていることがわかっている場合、slapi_entry_attr_find()を使用すると、属性へのポインタが直接戻されます。


注意:

仮想属性は、ロールとサービス・クラス(CoS)を使用する高度なエントリ管理のためにDirectory Serverによって生成され、実在属性とは対照的です。

CoSの属性などの仮想属性を処理する場合は、slapi_vattr_list_attrs ()を使用できます。この関数は、実在属性とエントリに属する仮想属性の完全なリストを提供します。


属性値に対する処理の繰返しは、次の例に示すように、slapi_attr_first_value_const ()slapi_attr_next_value_const()を一緒に使用して実行できます。

例4-4 属性値に対する処理の繰返し(testpreop.c)

#include "slapi-plugin.h"

int
testpreop_add(Slapi_PBlock * pb)
{
    Slapi_Entry * entry;               /* Entry to add            */
    Slapi_Attr  * attribute;           /* Entry attributes        */
    Slapi_Value ** values;             /* Modified, duplicate vals*/
    int         connId, opId, rc = 0;
    long        msgId;

    /* Get the entry. */
    rc |= slapi_pblock_get(pb, SLAPI_ADD_ENTRY,       &entry);
    rc |= slapi_pblock_get(pb, SLAPI_OPERATION_MSGID, &msgId);
    rc |= slapi_pblock_get(pb, SLAPI_CONN_ID,         &connId);
    rc |= slapi_pblock_get(pb, SLAPI_OPERATION_ID,    &opId);

    /* Prepend ADD to values of description attribute.            */
    rc |= slapi_entry_attr_find(entry, "description", &attribute);
    if (rc == 0) {                 /* Found a description, so...  */
        int nvals, i, count = 0;
        const Slapi_Value * value;

        slapi_attr_get_numvalues(attribute, &nvals);
        values = (Slapi_Value **)
            slapi_ch_malloc((nvals+1)*sizeof(Slapi_Value *));

        for (                          /* ...loop for value...    */
            i = slapi_attr_first_value_const(attribute, &value);
            i != -1;
            i = slapi_attr_next_value_const(attribute, i, &value)
        ) {                            /* ...prepend "ADD ".      */
            const char  * string;
            char        * tmp;
            values[count] = slapi_value_dup(value);
            string = slapi_value_get_string(values[count]);
            tmp    = slapi_ch_malloc(5+strlen(string));
            strcpy(tmp, "ADD ");
            strcpy(tmp+4, string);
            slapi_value_set_string(values[count], tmp);
            slapi_ch_free((void **)&tmp);
            ++count;
        }

        values[count] = NULL;

    } else {                           /* entry has no desc.      */
        slapi_log_info_ex(
            SLAPI_LOG_INFO_AREA_PLUGIN,
            SLAPI_LOG_INFO_LEVEL_DEFAULT,
            msgId,
            connId,
            opId,
            "testpreop_add in test-preop plug-in",
            "Entry has no description attribute.\n"
        );
    }

    rc = slapi_entry_attr_replace_sv(entry, "description", values);
    if (rc != 0) {
        slapi_log_info_ex(
            SLAPI_LOG_INFO_AREA_PLUGIN,
            SLAPI_LOG_INFO_LEVEL_DEFAULT,
            msgId,
            connId,
            opId,
            "testpreop_add in test-preop plug-in",
            "Description attribute(s) not modified.\n"
        );
    }
    slapi_valuearray_free(&values);

    return 0;
}

4.4 属性値の追加および削除

この項では、属性とその値を追加および削除する方法について説明します。

4.4.1 属性値の追加

属性名と属性値が文字列の場合、slapi_entry_add_string()を使用できることがあります。次の例では、まずDNを設定し、文字列値とともに属性を追加してエントリを構築しています。

例4-5 文字列属性値の追加(entries.c)

#include "slapi-plugin.h"

int
test_create_entry()
{
    Slapi_Entry * entry = NULL;        /* Original entry          */

    entry = slapi_entry_alloc();
    slapi_entry_set_dn(entry, slapi_ch_strdup("dc=example,dc=com"));
    slapi_entry_add_string(entry, "objectclass", "top");
    slapi_entry_add_string(entry, "objectclass", "domain");
    slapi_entry_add_string(entry, "dc", "example");

    /* Add code using the entry you created.....                  */

    slapi_entry_free(entry);

    return (0);
}

既存の値または文字列ではない値を処理する場合は、次の関数を使用できます。

  • slapi_entry_add_values_sv()を使用して、新しい値をエントリの属性に追加します。この関数は、新しい値の複製がすでに存在する場合にエラーを戻します。

  • slapi_entry_attr_merge_sv()を使用して、新しい値を複数値属性の既存の値に追加します。この関数は、新しい値の複製がすでに存在する場合にエラーを戻しません。

次の例は、slapi_entry_attr_merge_sv()を示しています。

例4-6 属性値のマージ(entries.c)

#include "slapi-plugin.h"

int
test_ldif()
{
    Slapi_Entry * entry = NULL;        /* Entry to hold LDIF      */
    Slapi_Value * values[2];           /* Attribute values        */

    entry = slapi_entry_alloc();

    /* Add code to transform an LDIF representation into an entry.*/

    /* Add a description by setting the value of the attribute.
     * Although this is overkill when manipulating string values,
     * it can be handy when manipulating binary values.           */
    values[0] = slapi_value_new_string("Description for the entry.");
    values[1] = NULL;
    if (slapi_entry_attr_merge_sv(entry,"description",values) != 0)
        /* Merge did not work if processing arrives here. */ ;

    slapi_entry_free(entry);

    return (0);
}

属性値がエントリに存在する場合は、slapi_entry_attr_merge_sv()が指定の値を既存の値のセットにマージします。属性が存在しない場合は、slapi_entry_attr_merge_sv()が指定の値で属性を追加します。

4.4.2 属性値の削除

slapi_entry_delete_string()またはslapi_entry_delete_values_sv()を使用して、属性値を削除します。

4.5 エントリのスキーマ準拠の検証

この項では、Directory Serverに認識されたディレクトリ・スキーマに関してエントリが有効なことをチェックする方法について説明します。slapi_entry_check ()を使用して、エントリのスキーマ準拠を検証します。関数の2つの引数は、次の例に示すように、パラメータ・ブロックへのポインタとエントリへのポインタです。

例4-7 スキーマ準拠のチェック(entries.c)

#include "slapi-plugin.h"

int
test_create_entry()
{
    Slapi_Entry * entry = NULL;        /* Original entry          */
    Slapi_Entry * ecopy = NULL;        /* Copy entry              */

    entry = slapi_entry_alloc();

    /* Add code to fill the entry, setting the DN and attributes. */

    ecopy = slapi_entry_dup(entry);
    slapi_entry_set_dn(ecopy, slapi_ch_strdup("dc=example,dc=org"));
    slapi_entry_add_string(ecopy, "description", "A copy of the orig.");
    
    /* Does the resulting copy comply with the schema?            */
    if (slapi_entry_schema_check(NULL, ecopy) == 0) {
        /* Resulting entry does comply. */ ;
    } else {
        /* Resulting entry does not comply. */ ;
    }

    slapi_entry_free(entry);
    slapi_entry_free(ecopy);

    return (0);
}

パラメータ・ブロックのポインタ引数はNULLであることに注意してください。パラメータ・ブロックのポインタ引数は、ほとんどの場合NULLのままです。プラグインをレプリケート環境で使用する場合は、引数を使用して、レプリケートされた操作に対するスキーマ準拠の検証を回避できます。

4.6 エントリ識別名の処理

この項では、次のことを実行するために識別名(DN)を処理する方法について説明します。

4.6.1 親DNおよびサフィックスDNの取得

次の例に示すように、slapi_dn_parent()関数を使用して親を戻し、slapi_dn_beparent()を使用してエントリに関連するサフィックスを戻します。

例4-8 エントリの親およびサフィックスの決定(dns.c)

#include "slapi-plugin.h"

int
test_dns(Slapi_PBlock * pb)
{
    char * bind_DN;                    /* DN being used to bind    */
    char * parent_DN;                  /* DN of parent entry       */
    char * suffix_DN;                  /* DN of suffix entry       */
    int    connId, opId, rc = 0;
    long   msgId;

    rc |= slapi_pblock_get(pb, SLAPI_BIND_TARGET,     &bind_DN);
    rc |= slapi_pblock_get(pb, SLAPI_OPERATION_MSGID, &msgId);
    rc |= slapi_pblock_get(pb, SLAPI_CONN_ID,         &connId);
    rc |= slapi_pblock_get(pb, SLAPI_OPERATION_ID,    &opId);
    if (rc != 0) return (-1);

    /* Get the parent DN of the DN being used to bind.             */
    parent_DN = slapi_dn_parent(bind_DN);
    slapi_log_info_ex(
        SLAPI_LOG_INFO_AREA_PLUGIN,
        SLAPI_LOG_INFO_LEVEL_DEFAULT,
        msgId,
        connId,
        opId,
        "test_dns in test-dns plug-in",
        "Parent DN of %s: %s\n", bind_DN, parent_DN
    );

    /* Get the suffix DN of the DN being used to bind.             */
    suffix_DN = slapi_dn_beparent(pb, bind_DN);
    if (suffix_DN != NULL) {
        slapi_log_info_ex(
            SLAPI_LOG_INFO_AREA_PLUGIN,
            SLAPI_LOG_INFO_LEVEL_DEFAULT,
            msgId,
            connId,
            opId,
            "test_dns in test-dns plug-in",
            "Suffix for user (%s) is (%s).\n", bind_DN, suffix_DN
        );
    }

    return rc;
}

ツリーが複雑でない場合、サフィックスDNと親DNは同じになる場合があることに注意してください。たとえば、bind_DNuid=bjensen,ou=People,dc=example,dc=comの場合、親はou=People,dc=example,dc=comになります。この場合、親はサフィックスと同じになります。

4.6.2 サフィックスがローカルで提供されているかどうかの判断

次の例に示すように、パラメータ・ブロックとルート・サフィックスDNに対するchar *を2つの引数として取る、slapi_dn_isbesuffix()関数を使用します。

例4-9 サフィックスがローカルかどうかの判断(dns.c)

#include "slapi-plugin.h"

int
test_dns(Slapi_PBlock * pb)
{
    char * bind_DN;                    /* DN being used to bind    */
    char * parent_DN;                  /* DN of parent entry       */
    char * suffix_DN;                  /* DN of suffix entry       */

    slapi_pblock_get(pb, SLAPI_BIND_TARGET, &bind_DN);

    /* Get the suffix DN of the DN being used to bind.             */
    suffix_DN = slapi_dn_beparent(pb, bind_DN);

    /* Climb the tree to the top suffix and check if it is local.  */
    while (suffix_DN != NULL &&
        !slapi_dn_isbesuffix(pb, suffix_DN)) {
        suffix_DN = slapi_dn_parent(suffix_DN);
    }
    if (suffix_DN != NULL) {
        /* Suffix is served locally. */ ;
    } else {
        /* Suffix is not served locally. */ ;
    }

    return 0;
}

slapi_dn_isbesuffix()を使用してツリーを上に移動することに注意してください。また、slapi_dn_parent()は、残っているDNがNULLになるまでDNで機能し続けることにも注意してください。親は、必ずしも実際のエントリに対応しません。

4.6.3 エントリDNの取得および設定

エントリDNを取得および設定するには、それぞれslapi_entry_get_dn()slapi_entry_set_dn()を使用します。「エントリのスキーマ準拠の検証」では、slapi_entry_set_dn ()を使用してエントリのコピーのDNを変更する方法について説明しています。slapi_ch_strdup ()を使用して、コピーで古いDNが使用されていないことを確認することに注意してください。

4.6.4 DNの正規化

余分な空白や大文字小文字の違いによって比較が失敗しないように、DNを比較する前にDNを正規化できます。次の例に示すように、slapi_dn_normalize()slapi_dn_normalize_case ()を使用してDNを正規化できます。

例4-10 DNの正規化(dns.c)

#include "slapi-plugin.h"

int
test_norm()
{
    char * test_DN;                    /* Original, not normalized */
    char * copy_DN;                    /* Copy that is normalized. */

    test_DN = "dc=Example,     dc=COM";/* Prior to normalization...*/

    /* When normalizing the DN with slapi_dn_normalize() and
     * slapi_dn_normalize_case(), the DN is changed in place.
     * Use slapi_ch_strdup() to work on a copy.                    */
    copy_DN = slapi_ch_strdup(test_DN);
    copy_DN = slapi_dn_normalize_case(copy_DN);

    return 0;
}

関数slapi_dn_normalize_case()は、引数として渡されたchar *DNに対して直接機能します。これにより、X.500で指定されているものの定義されていない「大文字小文字を区別しない一致」に対して、文字列を準備します。


注意:

元のものを変更しない場合は、slapi_ch_strdup()を使用して最初にコピーを作成します。


4.6.5 ユーザーはディレクトリ・マネージャかどうか

この質問には、slapi_dn_isroot()を使用して回答します。ただし、匿名ユーザーについては、ディレクトリのスーパーユーザーのバインドは、特別なケースとして処理されます。このようなユーザーについては、事前操作のバインド・プラグインをコールする前に、サーバー・フロントエンドがバインドを処理します。