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

 testpwdstore.c

 This source file provides an example of a password storage scheme
 plug-in with trivial functions for encoding and comparing password
 attribute values.

 ACTIVATING THIS PLUG-IN
 -----------------------
 1. Build the library containing the plug-in.
 
 2. Configure the server to load the plug-in.
 
    $ dsconf create-plugin -H <lib-path> -F xor_init -Y pwdstoragescheme "XOR"
    $ dsconf set-plugin-prop "XOR" feature:xor-password-storage-scheme version:7.0 desc:"Exclusive-or example (XOR)"
    $ dsconf enable-plugin "XOR"
    Directory Server needs to be restarted for changes to take effect
    $ dsadm restart <inst-path>

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

static char * name           ="XOR";   /* Storage scheme name */
static Slapi_PluginDesc desc = {
    "xor-password-storage-scheme",     /* Plug-in identifier      */
    "Oracle Corporation (test)",       /* vendor name             */
    "11.1.1.3.0",                      /* plug-in revision number */
    "Exclusive-or example (XOR)"       /* Plug-in description     */
};

#define PREFIX_START '{'
#define PREFIX_END   '}'

/* Encode a password.
   Server frees memory in which encoded password is returned. */
static char *
xorenc(char * pwd)
{
    char * tmp    = NULL;              /* Used for encoding   */
    char * head   = NULL;              /* Encoded password    */
    char * cipher = NULL;              /* Prefix, then pwd    */
    int i, len;
  
    /* Allocate space to build the encoded password           */
    len = strlen(pwd);
    tmp = slapi_ch_malloc(len + 1);
    if (tmp == NULL) return NULL;

    memset(tmp, '\0', len + 1);
    head = tmp;

    /* Encode. This example is not secure by any means.       */
    for (i = 0; i < len; i++, pwd++, tmp++) *tmp = *pwd ^ 42;
  
    /* Add the prefix to the cipher                           */
    if (tmp != NULL) {
        cipher = slapi_ch_malloc(3 + strlen(name) + strlen(head));
        if (cipher != NULL) {
            sprintf(cipher,"%c%s%c%s",PREFIX_START,name,PREFIX_END,head);
        }
    }
    slapi_ch_free((void **) &head);
  
    return (cipher);                   /* Server frees cipher */
}

/* Compare password provided with stored, encoded password.   */
static int 
xorcmp(char * userpwd, char * dbpwd)
{
    /* Check the correspondence of the two char by char       */       
    int i, len = strlen(userpwd);
    for (i = 0; i < len; i++) {
        if ((userpwd[i] ^ 42) != dbpwd[i])
            return 1;                  /* Different passwords */
    } 
    return 0;                          /* Identical passwords */
}

/* Register the plug-in with the server                       */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
xor_init(Slapi_PBlock * pb)
{
    int rc = 0;                        /* 0 means success     */
    rc |= slapi_pblock_set(            /* Plug-in API version */
        pb,
        SLAPI_PLUGIN_VERSION,
        (void *) SLAPI_PLUGIN_CURRENT_VERSION
    );
    rc |= slapi_pblock_set(            /* Plug-in description */
        pb,
        SLAPI_PLUGIN_DESCRIPTION,
        (void *) &desc
    );
    rc |= slapi_pblock_set(            /* Storage scheme name */
        pb,
        SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
        (void *) name
    );
    rc |= slapi_pblock_set(            /* Encode password     */
        pb,
        SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
        (void *) xorenc
    );
    rc |= slapi_pblock_set(            /* Compare password    */
        pb,
        SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
        (void *) xorcmp
    );
    rc |= slapi_pblock_set(            /* Never decode pwd    */
        pb,
        SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN,
        NULL
    );
    return rc;
}
