/*
 * 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.
 */
/************************************************************

 pwdcheck.c

 This example provides a trivial plug-in to check password values.

 TRYING 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 pwdcheck_init -Y passwordcheck "Trivial Password Check"
    $ dsconf enable-plugin "Trivial Password Check"
    Directory Server needs to be restarted for changes to take effect
    $ dsadm restart <inst-path>

 4. Force strong password checking, but do not use the default plug-in.

    $ dsconf set-server-prop pwd-check-enabled:on pwd-strong-check-enabled:off

 5. Modify a userPassword and observe the results.

    $ cat quentin.ldif
    dn: uid=qcubbins,ou=People,dc=example,dc=com
    objectclass: top
    objectclass: person
    objectclass: organizationalPerson
    objectclass: inetOrgPerson
    uid: qcubbins
    givenName: Quentin
    sn: Cubbins
    cn: Quentin Cubbins
    mail: quentin.cubbins@example.com
    userPassword: secret12

    $ ldapmodify -a -p 1389 -D uid=kvaughan,ou=people,dc=example,dc=com -w bribery -f quentin.ldif
    adding new entry uid=qcubbins,ou=People,dc=example,dc=com
    ldap_add_s: Constraint violation

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

Slapi_PluginDesc pwd_desc = { 
    "Trivial Password Check",
    "Oracle Corporation (test)",       /* vendor name             */
    "11.1.1.3.0",                      /* plug-in revision number */
    "Sample password check plug-in"
};

/* Reject password values equal to "secret12".               */
static int
check_pwd(Slapi_PBlock * pb)
{
    Slapi_Value ** pwdvals = NULL;
    int            is_repl, is_intl, i, rc = 0;

    rc |= slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl);
    rc |= slapi_pblock_get(pb, SLAPI_IS_INTERNAL_OPERATION,   &is_intl);
    rc |= slapi_pblock_get(pb, SLAPI_PASSWDCHECK_VALS,        &pwdvals);

    if (rc != 0) {
        slapi_log_error_ex(
            42L,        /* Use a unique ID in real life.   */
            SLAPI_LOG_NO_MSGID,
            SLAPI_LOG_NO_CONNID,
            SLAPI_LOG_NO_OPID,
            "Sample password check plug-in",
            SLAPI_INTERNAL_ERROR,
            "Could not get PBlock values (error %d).\n",
            rc
        );
        slapi_send_ldap_result(
            pb,
            LDAP_OPERATIONS_ERROR,
            NULL,
            "Internal parameter error",
            0,
            NULL
        );
        return -1;       /* failure: LDAP result sent directly to client */
    }

    /* Do not interfere with replication and internal operations. */
    if (is_repl || is_intl) return 0; /* success */

    /* Do not check values if none exist. */
    if (pwdvals == NULL) return 0; /* success */

    /* Iterate through the NULL terminated array of candidate password
       values, failing the operation should any supplied value not
       satisfy the quality criteria. */
    for (i=0 ; pwdvals[i] != NULL; i++) {
        const char * password = slapi_value_get_string(pwdvals[i]);
        if (strcmp("secret12", password) == 0) {
            slapi_pblock_set(pb, SLAPI_RESULT_TEXT,
               slapi_ch_strdup("invalid password syntax: Bad password!"));
            return 1; /* reject: failure handled by the core password policy */
        }
    }
    return 0;                   /* success */
}

#ifdef _WIN32
__declspec(dllexport)
#endif
int
pwdcheck_init(Slapi_PBlock * pb)
{
    int rc = 0;
    rc |= slapi_pblock_set(
                pb,
                SLAPI_PLUGIN_VERSION,
                SLAPI_PLUGIN_CURRENT_VERSION
            );

    rc |= slapi_pblock_set(
                pb,
                SLAPI_PLUGIN_DESCRIPTION,
                (void *) &pwd_desc
            );

    rc |= slapi_pblock_set(
                pb,
                SLAPI_PLUGIN_PASSWDCHECK_FN,
                (void *) check_pwd
            );
    return rc;
}
