/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved
 * Use of this product is subject to license terms.
 */
/************************************************************

 dns.c

 This source file demonstrates how to manipulate DNs.

 ACTIVATING THIS PLUG-IN
 -----------------------
 1. Build the library containing the plug-in.

 2. Configure the server to log plug-in messages.

    $ dsconf set-log-prop error level:err-plugins

 3. Configure the server to load the plug-in.
     
    $ dsconf create-plugin -H <lib-path> -F dns_init -Y preoperation "Test DNs"
    $ dsconf set-plugin-prop "Test DNs" feature:test-dns version:7.0 desc:"Sample plug-in for working with DNs"
    $ dsconf enable-plugin "Test DNs"
    Directory Server needs to be restarted for changes to take effect
    $ dsadm restart <inst-path>

************************************************************/
#include <stdio.h>
#include <string.h>
#include "slapi-plugin.h"

Slapi_PluginDesc dns_desc = {
    "test-dns",                           /* plug-in identifier      */
    "Oracle Corporation (test)",          /* vendor name             */
    "11.1.1.3.0",                         /* plug-in revision number */
    "Sample plug-in for working with DNs" /* description             */
};

/* Normalize a test DN.                                            */ 
int
test_norm()
{
    char * test_DN;                    /* Original, not normalized */
    char * copy_DN;                    /* Copy that we normalize   */

    test_DN = "dc=Example,     dc=COM";
    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_norm in test-dns plug-in",
        "Test DN before normalization: %s\n", test_DN
    );

    /* 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);
    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_norm in test-dns plug-in",
        "Test DN after normalization: %s\n", copy_DN
    );

    return 0;
}
    
/* Manipulates the bind DN and related information.                */
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);

    /* Check whether bind DN is the directory superuser. 
     * Note that pre-bind functions are only called when the
     * bind DN is that of a regular user. The front end
     * handles binds by the directory superuser.                   */
    if (!slapi_dn_isroot(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",
            "Regular user (%s) binding now.\n", bind_DN
        );
    }

    /* 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
        );
    }

    /* 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) {
        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 (%s) for bind DN (%s) served locally.\n",
            suffix_DN, bind_DN
        );
    } else {
        slapi_log_info_ex(
            SLAPI_LOG_INFO_AREA_PLUGIN,
            SLAPI_LOG_INFO_LEVEL_DEFAULT,
            msgId,
            connId,
            opId,
            "test_dns in test-dns plug-in",
            "Bind DN (%s) not served locally.\n", bind_DN
        );
    }

    return rc;
}

/* Register the plug-in with the server                            */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
dns_init(Slapi_PBlock * pb)
{
    int rc = 0;                        /* 0 means success          */
    rc |= slapi_pblock_set(            /* Plug-in API version      */
        pb,
        SLAPI_PLUGIN_VERSION,
        SLAPI_PLUGIN_CURRENT_VERSION
    );
    rc |= slapi_pblock_set(            /* Plug-in description      */
        pb,
        SLAPI_PLUGIN_DESCRIPTION,
        (void *) &dns_desc
    );
    rc |= slapi_pblock_set(            /* Startup function         */
        pb,
        SLAPI_PLUGIN_START_FN,
        (void *) test_norm
    );
    rc |= slapi_pblock_set(            /* Pre-bind function        */
        pb,
        SLAPI_PLUGIN_PRE_BIND_FN,
        (void *) test_dns
    );
    return rc;
}
