AF:
NF:0
PS:10
SRH:1
SFN:
DSR:
MID:<20080520112954.5024f4e8@ripper.onstor.net>
CFG:
PT:0
S:andy.sharp@onstor.com
RQ:
SSV:onstor-exch02.onstor.net
NSV:
SSH:
R:<ronb@onstor.com>
MAID:1
X-Sylpheed-Privacy-System:
X-Sylpheed-Sign:0
SCF:#mh/Mailbox/sent
X-Sylpheed-End-Special-Headers: 1
Date: Tue, 20 May 2008 11:30:06 -0700
From: Andrew Sharp <andy.sharp@onstor.com>
To: Ron Bhanukitsiri <ronb@onstor.com>
Subject: help needed testing idmap fix
Message-ID: <20080520113006.47a83bf9@ripper.onstor.net>
Organization: Onstor
X-Mailer: Sylpheed-Claws 2.6.0 (GTK+ 2.8.20; x86_64-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="MP_u4bOGzT9BMtiAZ46A6s/fK4"

--MP_u4bOGzT9BMtiAZ46A6s/fK4
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi Ron,

I think I need your help testing a fix I've done for

TED23242 idmap list is limited to 511 entries

because it requires a setup that I wouldn't have a clue how to get
going, namely windows domain controller ldap something something.

Care to take a shot at it?  Perfarce is down so I can't send you the
changelist, but I can attach the two files in question.  At the very
least I'd like to know that I haven't broken idmap show command for
just a normal amount of idmap entries, if you know what I mean.  If
I've also fixed the bug, that would be a bonus.

The files are for the dev branch, and yes, they do compile ~:^)

Thanks,

a

--MP_u4bOGzT9BMtiAZ46A6s/fK4
Content-Type: text/x-csrc; name=cluster-idmap-api.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=cluster-idmap-api.c

/* vi:ts=4
 *-----------------------------------------------------------------
 *
 * Name:        cluster-idmap-api.c
 *
 * RCS:  $Id: $
 *
 * Copyright (C) 2003, OnStor Inc.
 *
 * Description:	Contains routines to save and restore identity 
 *              mapping rules to & from cluster database.
 *
 * Created by:  Shaun Hui
 *
 * Date Created: 04/08/03
 *
 *-----------------------------------------------------------------
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "nfx-incl.h"

#include "../ssc-cluster/cluster-api.h"
#include "../ssc-cluster/cluster-idmap-api.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif


/*--------------------------------------------------------------------
 * Static function prototypes.
 *--------------------------------------------------------------------
 */
static int32
cluster_makeIdmapKey(  uint8			*key, 
					   uint32 			*keyLen,
					   clusDb_recType_t	recType,
					   uint8			*ruleStr,
					   uint32 			ruleLen);


static int32
cluster_makeIdmapRevCntrKey(clusDb_recType_t recType,
                            uint8            *key, 
                            uint32           *keyLen);


#define REC_ARRAY_BUFF_SIZE		4096


/*--------------------------------------------------------------------
 * Routine : cluster_makeIdmapRevCntrKey
 *
 * Description:
 *   Make a unique counter table key used for idmap rules revision generation
 *   One counter table per cluster for the user rules and one for the group
 *   rules.
 *
 * Arguments:
 *
 *   recType  - CLUSDB_REC_TYPE_IDMAP_GROUP_REV_CNTR or
 *              CLUSDB_REC_TYPE_IDMAP_USER_REV_CNTR
 *   key      - stores result of key string
 *   keyLen   - set to len of key if success.
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 *
 *--------------------------------------------------------------------
 */
static int32
cluster_makeIdmapRevCntrKey(clusDb_recType_t recType,
                            uint8            *key,
                            uint32           *keyLen )
{
    char    *typeStr;


    typeStr = cluster_getRecTypeStr( recType );
    if (typeStr == NULL)
        return NFX_ERR;

    /*-------------------------------------
     * Copy type str as part of key.
     *-------------------------------------
     */
    sprintf(key, "%s", typeStr );

    *keyLen = strlen(key);

    return NFX_OK;
}


/*--------------------------------------------------------------------
 * Routine : cluster_IdmapRulesRevision
 *
 * Description:
 *   Get user or group idmap rules revision.
 *   If requested, increment the counter before returning it.
 *
 * Arguments:
 *   
 *   idmapType - user or group
 *   increment - TRUE: the revision number needs to be incremented
 *   idmapRev  - set to idmap rules revision, once incremented if
 *               requested
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 *
 *--------------------------------------------------------------------
 */
int32
cluster_IdmapRulesRevision(authen_idMap_t   idmapType,
                           boolean          increment,
                           uint32           *idmapRev )
{
    cluster_rcode_t     code;
    clusDb_recType_t    recType;
    clusDb_recId_t      recId;
    clusDb_recEntry_t   parentEntry;
    uint64              counter;
    uint32              keyLen;
    uint8               key[CLUSTER_MAX_KEY_LEN];

    recType = (idmapType == authen_userIdMap) ?
               CLUSDB_REC_TYPE_IDMAP_USER_REV_CNTR :
               CLUSDB_REC_TYPE_IDMAP_GROUP_REV_CNTR;

    /*-------------------------------------
     * Make counter key
     *-------------------------------------
     */
    if (cluster_makeIdmapRevCntrKey(recType, key, &keyLen ) != NFX_OK)
        return CLUSTER_RCODE_NOT_FOUND;

    /*-------------------------------------
     * Get idmap counter table record Id
     *-------------------------------------
     */
    code = cluster_getRecordIdByKey(recType, &recId, keyLen, key);

    /*-------------------------------------
     * Check for error, except not found.
     *-------------------------------------
     */
    if ((code) && (code != CLUSTER_RCODE_NOT_FOUND))
        return NFX_ERR;


    /*-------------------------------------
     * If no idmap counter table, create one.
     *-------------------------------------
     */
    if (code == CLUSTER_RCODE_NOT_FOUND)
    {
        /*-------------------------------------
         * Get cluster record Id as parent.
         *-------------------------------------
         */
        if (cluster_getClusterRecId( &recId ) != NFX_OK)
            return NFX_ERR;

        /*-------------------------------------
         * Make idmap counter key
         *-------------------------------------
         */
        if (cluster_makeIdmapRevCntrKey(recType, key, &keyLen ) != NFX_OK)
            return CLUSTER_RCODE_NOT_FOUND;

        /*-------------------------------------
         * parent record is cluster.
         *-------------------------------------
         */
        parentEntry.recType = CLUSDB_REC_TYPE_CLUSTER;
        parentEntry.recId   = recId;

        /*------------------------------------------------------
         * Create the counter as infinite limit and don't reuse
         *------------------------------------------------------
         */
        code = cluster_createCounterTable(recType,
                                          &recId,
                                          keyLen,
                                          key,
                                          CLUSTER_IDMAP_REV_MIN,
                                          CLUSTER_IDMAP_REV_MAX,
                                          0,
                                          1,
                                          &parentEntry);

        if (code)
            return NFX_ERR;
    }

    /*------------------------------------------
     * idmap counter table found or created.
     *------------------------------------------
     */
    if (increment)  {
        /*------------------------------------------
         * increment the counter and get its value.
         *------------------------------------------
         */
        code  = cluster_allocateCounter(recType, recId, &counter);
    } else {
        /*------------------------------------------
         * just get the counter value.
         *------------------------------------------
         */
        code  = cluster_getCounterInfo(recType, recId, &counter);
    }
    if (code)
        return NFX_ERR;

    /*-------------------------------------
     * Return counter as idmap id.
     *-------------------------------------
     */
    *idmapRev= (uint32)counter;

    return NFX_OK;
}




/*--------------------------------------------------------------------
 * Routine : cluster_makeIdmapKey
 *
 * Description:
 *   Make a unique idmap control or rule record key using 
 *   type and rule str as key.
 *
 * Arguments:
 *
 *   key      - stores result of key string
 *   keyLen   - sets to len of key if success.
 *   idmapType- user or group
 *   ruleStr  - ptr to rule str
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 *
 *--------------------------------------------------------------------
 */
static int32
cluster_makeIdmapKey(  uint8			*key, 
					   uint32 			*keyLen,
					   clusDb_recType_t	recType,
					   uint8			*ruleStr,
					   uint32 			ruleLen)
{
    char    *typeStr;
    uint32  typeLen;

    typeStr = cluster_getRecTypeStr( recType );
    if (typeStr == NULL)
        return NFX_ERR;

    typeLen = strlen(typeStr);
    
    /*-------------------------------------
     * Make sure key buf is big enough.
     *-------------------------------------
     */
    if (( ruleLen + typeLen ) > CLUSTER_MAX_KEY_LEN)
        return NFX_ERR;
 
    /*-------------------------------------
     * Copy  type str as part of key.
     *-------------------------------------
     */
    memcpy(key, typeStr, typeLen);
 
    /*-------------------------------------
     * Advance ptr beyond typeStr
     * Copy rule as part of key.
     *-------------------------------------
     */
    key += typeLen;
    memcpy(key, ruleStr, ruleLen);

    /*-------------------------------------
     * Set the key length.
     *-------------------------------------
     */
    *keyLen = (ruleLen + typeLen);

	return NFX_OK;
}


/*--------------------------------------------------------------------
 * Routine : cluster_createIdmap
 *
 * Description:
 *   Creates an ID mapping rule  record in cluster DB.
 *
 * Arguments:
 *
 *   recType       - group or user db record type.
 *   recId         - set to record id, if success
 *   parentRecType - parent record type
 *   parentRecId   - parent record ID
 *   ruleStr       - ptr to id mapping rule string 
 *   ruleLen       - length of id mapping rule string 
 *
 * Return Value:
 *
 *  CLUSTER_RCODE_OK  - success
 *  See cluster_rcode_t for error
 *
 *--------------------------------------------------------------------
 */
static cluster_rcode_t
cluster_createIdmapRule(  clusDb_recType_t		recType,
					   	  clusDb_recId_t		*recId,
					   	  clusDb_recType_t		parentRecType,
					   	  clusDb_recId_t		parentRecId,
					   	  uint8					*ruleStr,
					   	  uint32				ruleLen)
{

    cluster_rcode_t     code;
    clusDb_recEntry_t   parentEntry;
	uint32				keyLen;
	uint8				key[CLUSTER_MAX_KEY_LEN];
	

    /*-------------------------------------
     * Make key with idmap type & ruleStr 
     *-------------------------------------
     */
	if (cluster_makeIdmapKey(key, 
							&keyLen, 
							recType, 
							ruleStr,
							ruleLen) != NFX_OK)
		return CLUSTER_RCODE_ERROR;

    /*-------------------------------------
     * set up rule parent entry.
     *-------------------------------------
     */
	parentEntry.recType = parentRecType;
	parentEntry.recId   = parentRecId;

    /*-------------------------------------
     * create rule record in cluster db.
     *-------------------------------------
     */
    code = cluster_createRecord( recType,
                                 recId,
                                 keyLen,
                                 key,
                                 ruleLen,
                                 (uint8 *)ruleStr,
                                 1,
								 &parentEntry);
	return code;	
}


/*--------------------------------------------------------------------
 * Routine : cluster_deleteIdmapRule
 *
 * Description: 
 *   Deletes an mapping rule record from cluster DB.
 *   
 * Arguments:
 *
 *   idmapType - user or group
 *   index     - display position to be deleted.
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 * 
 *--------------------------------------------------------------------
 */
int32
cluster_deleteIdmapRule(authen_idMap_t 	idmapType,
					    int32			index)
{
	uint32					numRec;
	uint32					idx;
	int32					rc;
    cluster_rcode_t	    	code;
    clusDb_recType_t	   	childRecType;
    clusDb_recId_t	    	currRecId;
    clusDb_recType_t	   	currRecType;
    clusDb_recId_t	    	parentRecId;
    clusDb_recType_t	   	parentRecType;
    clusDb_recEntry_t   	*pRecEntry;

	childRecType = (idmapType == authen_userIdMap) ? 
				    CLUSDB_REC_TYPE_IDMAP_USER     :
				    CLUSDB_REC_TYPE_IDMAP_GROUP;

	rc = NFX_OK;

    /*-------------------------------------
     * Allocate record array buffer.
     *-------------------------------------
     */
    pRecEntry = malloc(REC_ARRAY_BUFF_SIZE);
    if (pRecEntry == NULL)
        return NFX_ERR;
	
    /*-------------------------------------
     * Get cluster record Id as parent.
     *-------------------------------------
     */
    code = cluster_getClusterRecId( &currRecId );
	if (code)
	{
		rc = NFX_ERR;
		goto delIdmapDone;
	}	

    /*-------------------------------------
     * We are using parent-child array to
     * chain rule records.
     * Only the 1st rule record is child 
	 * of a cluster record.
     * Subseqent rule record is child 
	 * of a rule record.
     *-------------------------------------
     */
	currRecType = CLUSDB_REC_TYPE_CLUSTER;
	numRec      = 0;

	for (idx = 0; idx < index; idx++)
	{
	    /*-------------------------------------
	     * Get child record of idmap rule type
	     *-------------------------------------
	     */
	    code = cluster_getChildRecords( currRecType,
										currRecId, 
	                                    childRecType,
	                                    0,
	                                    REC_ARRAY_BUFF_SIZE,
	                                    &numRec,
                                        NULL,
	                                    pRecEntry);

		if (code)
		{
			rc = NFX_ERR;
			goto delIdmapDone;
		}

	    /*-------------------------------------
	     * If no child record found, reached end 
		 * of list in db.  (idx < index)
	     *-------------------------------------
	     */
		if (numRec == 0)
		{
			rc = NFX_ERR;
			goto delIdmapDone;
		}

	    /*-------------------------------------
	     * Use current record as parent.
	     *-------------------------------------
	     */
		parentRecType = currRecType;
		parentRecId   = currRecId; 

	    /*-------------------------------------
	     * Use child as current record.
	     *-------------------------------------
	     */
		currRecType = pRecEntry->recType;
		currRecId   = pRecEntry->recId;
	
	}


    /*-------------------------------------
     * currRecId is record to be deleted.
	 * Check if it has any child record.
     *-------------------------------------
     */
    code = cluster_getChildRecords( currRecType,
									currRecId, 
                                    childRecType,
                                    0,
                                    REC_ARRAY_BUFF_SIZE,
                                    &numRec,
                                    NULL,
                                    pRecEntry);

	if (code)
	{
		rc = NFX_ERR;
		goto delIdmapDone;
	}

	if (numRec)
	{
	    /*-------------------------------------
	     * Change child record parent from
		 * current record to parent rec.
	     *-------------------------------------
	     */
		code = cluster_transferParentLink( 
							pRecEntry->recType, // child type
							pRecEntry->recId,	// child id
							currRecType,  		// from parent type
							currRecId,    		// from parent id
							parentRecType,  	// to parent type
							parentRecId); 		// to parent Id
		if (code)
		{
			rc = NFX_ERR;
			goto delIdmapDone;
		}
	}


    /*-------------------------------------
     * Delete current rule record from cluster db.
     *-------------------------------------
     */
    code = cluster_deleteRecordById( currRecType, currRecId);
	if (code)
	{
		rc = NFX_ERR;
		goto delIdmapDone;
	}

delIdmapDone:

	if (pRecEntry)
		free(pRecEntry);

	return (rc);

}


/*--------------------------------------------------------------------
 * Routine : cluster_addIdmapRule
 *
 * Description:
 *   Adds an ID mapping rule  record in cluster DB.
 *   If insert is set, creates a new record and put it BEFORE record
 *   at index position. Parent & child array is used to chain record
 *   in sequence.
 *
 * Arguments:
 *
 *   idmapType     - group or user mapping rule
 *   insert        - insert(1) or replace(0) record 
 *   index         - record idx to insert before
 *   ruleStr       - ptr to id mapping rule string 
 *   ruleLen       - length of id mapping rule string 
 *
 * Return Value:
 *
 *  CLUSTER_RCODE_OK  - success
 *  See cluster_rcode_t - error
 *
 *--------------------------------------------------------------------
 */
cluster_rcode_t
cluster_addIdmapRule(authen_idMap_t 	idmapType,
					   boolean			insert,
					   int32			index,
					   uint8			*ruleStr,
					   uint32			ruleLen)
{
	uint32					numRec;
	uint32					idx;
    cluster_rcode_t	    	code;
    clusDb_recId_t	    	newRecId;
    clusDb_recType_t	   	newRecType;
    clusDb_recId_t	    	currRecId;
    clusDb_recType_t	   	currRecType;
    clusDb_recId_t	    	parentRecId;
    clusDb_recType_t	   	parentRecType;
    clusDb_recEntry_t   	*pRecEntry;


	newRecType = (idmapType == authen_userIdMap) ? 
				  CLUSDB_REC_TYPE_IDMAP_USER     :
				  CLUSDB_REC_TYPE_IDMAP_GROUP;

    /*-------------------------------------
     * Allocate record array buffer.
     *-------------------------------------
     */
    pRecEntry = malloc(REC_ARRAY_BUFF_SIZE);
    if (pRecEntry == NULL)
        return CLUSTER_RCODE_ERROR;
	
    /*-------------------------------------
     * Get cluster record Id as parent.
     *-------------------------------------
     */
    code = cluster_getClusterRecId( &currRecId );
	if (code)
	{
		goto addIdmapDone;
	}	

    /*-------------------------------------
     * We are using parent-child array to
     * chain rule records.
     * Only the 1st rule record is child 
	 * of a cluster record.
     * Subseqent rule record is child 
	 * of a rule record.
     *-------------------------------------
     */
	currRecType = CLUSDB_REC_TYPE_CLUSTER;
	numRec      = 0;

	for (idx = 0; idx < index; idx++)
	{
	    /*-------------------------------------
	     * Get child record of idmap rule type
	     *-------------------------------------
	     */
	    code = cluster_getChildRecords( currRecType,
										currRecId, 
	                                    newRecType,
	                                    0,
	                                    REC_ARRAY_BUFF_SIZE,
	                                    &numRec,
                                        NULL,
	                                    pRecEntry);

		if (code)
		{
			goto addIdmapDone;
		}

	    /*-------------------------------------
	     * If no child record found, reached end 
		 * of list in db.  (idx < index)
		 * Create rule record and insert at the end. 
	     *-------------------------------------
	     */
		if (numRec == 0)
		{
			code = cluster_createIdmapRule(  newRecType, 
									   	   &newRecId, 
										   currRecType, 
										   currRecId, 
										   ruleStr, 
										   ruleLen );
			goto addIdmapDone;

		}

	    /*-------------------------------------
	     * Use current record as parent.
	     *-------------------------------------
	     */
		parentRecType = currRecType;
		parentRecId   = currRecId; 

	    /*-------------------------------------
	     * Use child as current record.
	     *-------------------------------------
	     */
		currRecType = pRecEntry->recType;
		currRecId   = pRecEntry->recId;
	
	}


	if (!insert)
	{
	    /*-------------------------------------
	     * Not insert, just replace rule 
	     * contents of current record.
	     *-------------------------------------
	     */
    	code = cluster_updateRecordDataById(currRecType,
                                          	currRecId,
                                          	ruleLen,
                                          	ruleStr);

		goto addIdmapDone;

	}
	else
	{
	    /*-------------------------------------
	     * Insert before current record.
	     * Create new record with parent of 
	     * current record.
	     *-------------------------------------
	     */
		code = cluster_createIdmapRule(  newRecType, 
									   &newRecId, 
									   parentRecType, 
									   parentRecId, 
									   ruleStr, 
									   ruleLen );
		if (code != CLUSTER_RCODE_OK)
			goto addIdmapDone;

	    /*-------------------------------------
	     * Change current record parent to new record.
	     *-------------------------------------
	     */
		code = cluster_transferParentLink( 
								currRecType, 	// child type
								currRecId,		// child id
								parentRecType,  // from parent type
								parentRecId,    // from parent id
								newRecType, 	// to parent type
								newRecId); 		// to parent Id
	}

addIdmapDone:

	if (pRecEntry)
		free(pRecEntry);

	return (code);


}


/*--------------------------------------------------------------------
 * Routine : cluster_getIdmapRuleList
 *
 * Description:
 *   Returns a list of ID map record Id of given type.
 *
 * Arguments:
 *
 *   idmapType - user or group 
 *   buffSize  - size of record entry buffer
 *   pNumRec   - input: the record number (ordinal 0) of the first
 *               desired record
 *               output: success - record number of last record in
 *                                 the buffer -- suitable for input
 *                       failure - 0
 *   pRecList  - buffer to store record entries.
 *               Caller is responsible for alloc & free.
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 *
 *--------------------------------------------------------------------
 */
int32
cluster_getIdmapRuleList(authen_idMap_t 	idmapType, 
					     uint32				buffSize,
					     uint32				*pNumRec,
					     void				*pRecList)
{
	uint32					numRec;
	uint32                  startRec;
	uint32                  totalRec;
	int32					rc;
    cluster_rcode_t	    	code;
    clusDb_recType_t	   	recType;
    clusDb_recId_t	    	currRecId;
    clusDb_recType_t	   	currRecType;
    clusDb_recEntry_t   	*pRecEntry;


	rc = NFX_OK;
	pRecEntry = pRecList;
	recType   = (idmapType == authen_userIdMap) ?
				CLUSDB_REC_TYPE_IDMAP_USER :
				CLUSDB_REC_TYPE_IDMAP_GROUP;

    /*-------------------------------------
     * Get cluster record Id as parent.
     *-------------------------------------
     */
    code = cluster_getClusterRecId( &currRecId );
	if (code)
	{
		rc = NFX_ERR;
		goto done;
	}	

    /*-------------------------------------
     * We are using parent-child array to
     * chain rule records.
     * Only the 1st rule record is child 
	 * of a cluster record.
     * Subseqent rule record is child 
	 * of a rule record.
     *-------------------------------------
     */
	currRecType = CLUSDB_REC_TYPE_CLUSTER;
	startRec    = *pNumRec;
	numRec      = 0;
	totalRec    = 0;

	do
	{
	    /*-------------------------------------
	     * Get child record of idmap rule type
	     *-------------------------------------
	     */
	    code = cluster_getChildRecords( currRecType,
										currRecId, 
	                                    recType,
	                                    0,
	                                    buffSize,
	                                    &numRec,
                                        NULL,
	                                    pRecEntry);

		if (code)
		{
			rc = NFX_ERR;
			goto done;
		}

	    /*-------------------------------------
	     * Use child as current record.
	     *-------------------------------------
	     */
		currRecType = pRecEntry->recType;
		currRecId   = pRecEntry->recId;
	
		pRecEntry  += numRec;
		totalRec   += numRec;

		if (numRec) {
			/*
			 * if we haven't gotten to the cursor yet, go back and
			 * get more records starting at the beginning of the buffer 
			 */
			if (totalRec <= startRec) {
				pRecEntry = pRecList;
				numRec = 0;
				continue;
			}
			/*
			 * if we have gotten to the cursor, move the records
			 * we are keeping to the start of the buffer
			 */
			if (startRec) {
				clusDb_recEntry_t *dstEntry;
				uint32 src;
				uint32 i;

				i = totalRec - startRec;
				src = numRec - i;
				dstEntry = pRecEntry - numRec;
				while (i && src) {
					*dstEntry = *(dstEntry + src);
					dstEntry++;
					i--;
				}
				pRecEntry -= src;
				numRec -= src;
				startRec = 0;
			}
		}

		buffSize   -= (numRec * sizeof(clusDb_recEntry_t));
		if (buffSize <= sizeof(clusDb_recEntry_t))
			goto done;

	    /*-------------------------------------
	     * If no child record found, reached end 
		 * of list in db.  
	     *-------------------------------------
	     */
	} while (numRec);

done:

	/*
	 * kind of dumb to have two, possibly conflicting,
	 * error return indicators, but ...
	 */
	if (rc == NFX_OK) {
		*pNumRec = totalRec;
	} else {
		*pNumRec = 0;
	}

	return (rc);
}


/*--------------------------------------------------------------------
 * Routine : cluster_showIdmapRule
 *
 * Description:
 *   Displays ALL ID map records in cluster db of given type.
 *
 * Arguments:
 *
 *   None.
 *
 * Return Value:
 *
 *  NFX_OK  - success
 *  NFX_ERR - error
 *
 *--------------------------------------------------------------------
 */
int32
cluster_showIdmapRule(authen_idMap_t 	idmapType)
{
	uint32					dataLen;
	uint32					numRec;
	uint32					idx;
	int32					rc;
	uint8					*typeStr;
	uint8					*ruleBufp;
    clusDb_recEntry_t   	*pRecList;

	pRecList = NULL;
	ruleBufp = NULL;

	if (idmapType == authen_userIdMap) 
	{
		typeStr = "user";
	}
	else
	{
		typeStr = "group";
	}

    /*-------------------------------------
     * Allocate record array buffer.
     *-------------------------------------
     */
    pRecList = malloc(REC_ARRAY_BUFF_SIZE);
    if (pRecList == NULL)
        return NFX_ERR;
	
    /*-------------------------------------
     * Get records list.
     *-------------------------------------
     */
	numRec = 0;
	if (cluster_getIdmapRuleList(idmapType, 
								REC_ARRAY_BUFF_SIZE,
					     		&numRec,
					     		pRecList) != NFX_OK)
	{
		rc = NFX_ERR;
		goto showIdmapDone;
	}

    /*-------------------------------------
     * Allocate rule buffer.
     *-------------------------------------
     */
    ruleBufp = malloc(CLUSTER_IDMAP_BUFF_SIZE);
    if (ruleBufp == NULL)
    {
		rc = NFX_ERR;
		goto showIdmapDone;
	}
	
    printf("Type  Index\n");
    printf("--------------------------------------------\n");
	for (idx=0; idx < numRec; idx++)
	{
		if (cluster_getRecordDataFromList(idx, 
										pRecList, 
										CLUSTER_IDMAP_BUFF_SIZE,
										&dataLen,
										ruleBufp ) != NFX_OK)
		{
			rc = NFX_ERR;
			goto showIdmapDone;
		}

		ruleBufp[dataLen] = '\0';
		printf("%-5s  %-3d  %s\n", typeStr, idx+1, ruleBufp);

	}

showIdmapDone:

	if (pRecList)
		free(pRecList);

	if (ruleBufp)
		free(ruleBufp);

	return (rc);
}


--MP_u4bOGzT9BMtiAZ46A6s/fK4
Content-Type: text/x-csrc; name=cmd_idmap.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=cmd_idmap.c

/* vi:ts=4
 *-----------------------------------------------------------------
 *
 * Name:
 *
 * RCS:  $Id: Exp $
 *
 * Copyright (C) 2001, Agile Storage, Inc.
 *
 * Description: identity mapping commands
 *
 * Created by:  Laurent Brard
 *
 * Date Created:
 *              23-Jan-2003 
 *
 *-----------------------------------------------------------------
 */
#include <sys/types.h>
#include <pwd.h>
#include <readline/history.h>
#include <grp.h>
#include <unistd.h>

#include "../ssc-zebra/zebra.h"
#include "command.h"
#include "vtysh.h"

#include "nfxsh.h"

#include "../sm-anpssc/anpssc-api.h"
#include "../ssc-nfxnis/nfxnis-api.h"
#include "../ssc-cluster/cluster-idmap-api.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif

#define IDMAPCMD "Identity mapping commands\n"

#define IDMAP_WIN_VALIDCHARS    " _."
#define IDMAP_WIN_INVALIDCHARS  "\"/\\[]:;|=,+*?<>\t"
#define IDMAP_WIN_WILDCHARS     "* \t"

#define IDMAP_UNIX_VALIDCHARS   "_."
#define IDMAP_UNIX_INVALIDCHARS ""
#define IDMAP_UNIX_WILDCHARS    "* \t"
#define IDMAP_SHOW_REC_SIZE     14
#define REC_ARRAY_BUFF_SIZE     4096


DEFUN   (add,
        add_cmd,
        "idmap (insert|edit) (user|group) INDEX",
        IDMAPCMD
        "Insert identity mapping (if map exists at that index, move it down)\n"
        "Edit identity mapping (if map exists at that index, replace it)\n"
        "This is a user identity mapping\n"
        "This is a group identity mapping\n"
        "Index where to insert/edit the identity mapping\n")
{
    boolean insert;
    authen_idMap_t type;
    int index;
    authen_idMapOp_t op;
    char idMapStr[512];
    char *p, *winId, *opStr, *unixId;
    char domain[sizeof(idMapStr)];
    int32 nameLen, ndx;
    char *unixDomName;
    authen_domCfg_t domcfg;
	cluster_rcode_t code;
    
    int rc = CMD_SUCCESS;

    if (*argv[0] == 'i')    {
        insert = TRUE;
    } else {
        insert = FALSE;
    }
    if (*argv[1] == 'u')    {
        type = authen_userIdMap;
    } else {
        type = authen_groupIdMap;
    }
    index = atoi(argv[2]);    
    if (index <= 0 || index > ID_MAP_CFG_IDXMAX) {
        printf("Invalid index\n");
        return CMD_ERR_FAILED;
    }

    printf(
    "Enter the %s mapping: windowsDomain\\name ==/<=/=> name@unixDomain\n"
    "                        (*=wildcard, name empty=no mapping)\n>", argv[1]);

    fgets(idMapStr, sizeof(idMapStr), stdin); 
    p = idMapStr;

    //Removing starting spaces
    while (isspace(*p)) p++;
    winId = p;

    //Looking for the operator
    if ((opStr = strchr(p, '<')) == NULL)  {
        if ((opStr = strchr(p, '=')) == NULL)   {
            printf("No operator defined\n");
            return CMD_ERR_FAILED;
        }
    }

    //Identifying the operator
    if (!memcmp(opStr, "==", 2))    {
        op = authen_idMapOp_BiDirect;
    } else {
        if (!memcmp(opStr, "=>", 2))    {
            op = authen_idMapOp_Win2Unix;
        } else {
            if (!memcmp(opStr, "<=", 2))    {
                op = authen_idMapOp_Unix2Win;
            } else {
                printf("Wrong operator\n");
                return CMD_ERR_FAILED;
            }
        }
    }
 
    //Removing windows identity trailing spaces
    p = opStr;
    do {
        *(p--) = '\0';
    } while (isspace(*p)); 

    //Basic windows identity syntax check
    if ((p = strchr(winId, '\\')) == NULL) {
        printf("Bad windows identity\n");
        return CMD_ERR_FAILED;
    }

    //Convert the Windows domain name to UPPERCASE - thats the way they are
    //stored.
    nameLen = (int32)(p - winId);
    for (ndx = 0; ndx < nameLen; ndx++) {
        domain[ndx] = toupper(winId[ndx]);
    }

    //Validate the Windows domain
    if ((!authen_isWildcardName(domain, nameLen)) &&
        (cluster_getDomain(domain,                 // *domName
                           nameLen,                // nameLen
                           authen_windowsDomain,   // domType
                           &domcfg,                // *cfgp
                           sizeof(domcfg))         // cfgSize
         != NFX_OK)) {
        printf("Unknown windows domain: %*.*s\n", nameLen, nameLen, winId);
        return CMD_ERR_FAILED;
    }

    //Validate the Windows user/group name
    p++;
    if ( authen_validateName( p,                         // *name
                              strlen(p),                 // nameLen
                              IDMAP_WIN_VALIDCHARS,      // *validChars
                              IDMAP_WIN_INVALIDCHARS,    // *invalidChars
                              IDMAP_WIN_WILDCHARS )      // *wildChars
         != NFX_OK ) {
        printf("Invalid characters in windows name: '%s'\n", p);
        return CMD_ERR_FAILED;
    }

    //Removing starting spaces
    p = opStr + 2;
    while (isspace(*p)) p++;
    unixId = p;
    
    //Basic unix identity syntax check
    if ((unixDomName = strchr(unixId, '@')) == NULL) {
        printf("Bad unix identity\n");
        return CMD_ERR_FAILED;
    }
    
    //Removing trailing spaces, CR and LF
    p += strlen(unixId) - 1;   
    while (isspace(*p)) *(p--) = '\0'; 
    
    //Validate the Unix domain
    unixDomName++;
    nameLen = strlen(unixDomName);
    if (!authen_isWildcardName(unixDomName, nameLen)) {
        if ((cluster_getDomain( unixDomName,        // *domName
                                nameLen,            // nameLen
                                authen_nisDomain,   // domType
                                &domcfg,            // *cfgp
                                sizeof(domcfg) )    // cfgSize	
             != NFX_OK ) &&
            (cluster_getDomain( unixDomName,        // *domName
                                nameLen,            // nameLen
                                authen_ldapDomain,  // domType
                                &domcfg,            // *cfgp
                                sizeof(domcfg) )    // cfgSize
             != NFX_OK )) {
            printf("Unknown unix domain: %*.*s\n", nameLen, nameLen, unixDomName);
            return CMD_ERR_FAILED;
        }
    }
   
    //Validate the Unix user/group name
    nameLen = (int32)((unixDomName - 1) - unixId);
    if ( authen_validateName( unixId,                    // *name
                              nameLen,                   // nameLen
                              IDMAP_UNIX_VALIDCHARS,     // *validChars
                              IDMAP_UNIX_INVALIDCHARS,   // *invalidChars
                              IDMAP_UNIX_WILDCHARS )     // *wildChars
         != NFX_OK ) {
        printf("Invalid characters in unix name: '%*.*s'\n",
               nameLen, nameLen, unixId);
        return CMD_ERR_FAILED;
    }

    code = authen_addIdMapRule(type, index, insert, winId, op, unixId);
        
	switch (code) {
        case CLUSTER_RCODE_DUPLICATE:
            printf("The record already exists \n");
            rc = CMD_ERR_FAILED;
            break;
        case CLUSTER_RCODE_OK:
            rc = CMD_SUCCESS;
            break;
        default:
            printf("Database update failed (error %d)\n", code);
            rc = CMD_ERR_FAILED;
    }
    
    return rc;
}

DEFUN   (delete,
        delete_cmd,
        "idmap delete (user|group) INDEX",
        IDMAPCMD
        "Delete an identity mapping\n"
        "This is a user identity mapping\n"
        "This is a group identity mapping\n"
        "Index of the identity mapping to delete\n")
{
    int rc = CMD_SUCCESS;
    authen_idMap_t type;
    int index;

    if (*argv[0] == 'u')    {
        type = authen_userIdMap;
    } else {
        type = authen_groupIdMap;
    }
    index = atoi(argv[1]);    
    if (index <= 0 || index > ID_MAP_CFG_IDXMAX) {
        printf("Invalid index\n");
        return CMD_ERR_FAILED;
    }
    if (authen_delIdMapRule(type, index)) {
        rc = CMD_ERR_FAILED;
    }

    return rc;
}


DEFUN   (notifyChange,
        notifyChange_cmd,
        "idmap notify change (user|group)",
        IDMAPCMD
        "Notify that an external configuration has changed identity mapping\n"
        "Authorization cache will be flushed and quota rebuild may be triggered\n"
        "The change applies to a user identity\n"
        "The change applies to a group identity\n")
{
    int rc = CMD_SUCCESS;
    authen_idMap_t type;

    if (*argv[0] == 'u')    {
        type = authen_userIdMap;
    } else {
        type = authen_groupIdMap;
    }
    if (authen_notifyIdMapRulesChange(type, NULL))  {
        rc = CMD_ERR_FAILED;
    }

    return rc;
}


DEFUN   (show,
        show_cmd,
        "idmap show (all|user|group)[-P PAGENUMBER [-S PAGESIZE]]",
        IDMAPCMD
        "Show identity mappings.\n"
        "All identity mappings.\n"
        "Just user identity mappings.\n"
        "Just group identity mappings.\n"
        "PageNumber(User|Group).\n"
        "PageNumber(User|Group).\n"
        "PageSize(User|Group).\n"
        "PageSize(User|Group).\n")
{
    int                     pageNo=0,pageSize=IDMAP_SHOW_REC_SIZE, c;
	uint32					dataLen;
	uint32					bufsize;
	uint32					numRec;
	uint32					idx;
	uint8					*typeStr;
	uint8					*ruleBufp;
    int                     iter, tot;
    clusDb_recType_t		recType;
    clusDb_recEntry_t       *pRecList;
    authen_idMap_t          idmapType[2];
	int                     rc = CMD_SUCCESS;


    switch(*argv[0]) {
        case 'a':
            idmapType[0] = authen_userIdMap;
            idmapType[1] = authen_groupIdMap;
            tot = 2;
                break;
        case 'u':
            idmapType[0] = authen_userIdMap;
            tot = 1;
                break;
        case 'g':
            idmapType[0] = authen_groupIdMap;
            tot = 1;
                break;
    }

    if (argc > 1) {
        optind = 1;
        /* extract the option values
         */
        while ((c = getopt (argc, argv, "P:S:")) != -1) {
            switch (c) {
                case 'P':
                    if (tot == 2) {
                        printf("Pagination applies for user"
                            " and group show only\n");
                        rc = CMD_ERR_FAILED;
						goto return_no_free;
                    }
                    pageNo=atoi(optarg);
                    if (pageNo <= 0) {
                        printf("Invalid page number\n");
                        rc = CMD_ERR_FAILED;
						goto return_no_free;
                    }
                    pageSize = IDMAP_SHOW_REC_SIZE;
                    break;
                case 'S':
                    pageSize=atoi(optarg);
                    if (pageSize <= 0) {
                        printf("Invalid page size\n");
                        rc = CMD_ERR_FAILED;
						goto return_no_free;
                    } else if (!pageNo) {
                        printf("Specify page number first\n");
                        rc = CMD_ERR_FAILED;
						goto return_no_free;
                    }
                    break;
                default:
                    printf("idmap show (all|user|group) "
                        "[-P PAGENUMBER [-S PAGESIZE]]\n");
					rc = CMD_ERR_FAILED;
					goto return_no_free;
            }
        }

        if (optind != argc) {
            printf("idmap show (all|user|group) "
                    "[-P PAGENUMBER [-S PAGESIZE]]\n");
			rc = CMD_ERR_FAILED;
			goto return_no_free;
        }
    }

	pRecList = NULL;
	ruleBufp = NULL;

    /*-------------------------------------
     * Allocate record array buffer.
     *-------------------------------------
     */
    pRecList = malloc(REC_ARRAY_BUFF_SIZE);
    if (pRecList == NULL) {
        printf("Memory insufficient\n");
		rc = CMD_ERR_FAILED;
		goto return_no_free;
    }

    /*-------------------------------------
     * Allocate rule buffer.
     *-------------------------------------
     */
    ruleBufp = malloc(REC_ARRAY_BUFF_SIZE);
    if (ruleBufp == NULL) {
        printf("Memory insufficient\n");
		rc = CMD_ERR_FAILED;
		goto return_free_reclist;
	}


    for (iter=0; iter < tot; iter++) {

		if (idmapType[iter] == authen_userIdMap) {
			recType = CLUSDB_REC_TYPE_IDMAP_USER;
			typeStr = "user";
		} else {
			recType = CLUSDB_REC_TYPE_IDMAP_GROUP;
			typeStr = "group";
		}

        bzero(pRecList, REC_ARRAY_BUFF_SIZE);
        bzero(ruleBufp, REC_ARRAY_BUFF_SIZE);

        /*-------------------------------------
         * Get records list.
         *-------------------------------------
         */
		numRec = 0;
		bufsize = REC_ARRAY_BUFF_SIZE;

        if (pageNo) {
            numRec = (pageNo-1) * pageSize;
            bufsize = pageSize * sizeof(clusDb_recEntry_t);
        }

		printf("Type  Index\n");
		printf("--------------------------------------------\n");
		for (;;) {
			int32 startRec;

			startRec = numRec;
			if (cluster_getIdmapRuleList(idmapType[iter],
									bufsize,
									&numRec,
									pRecList) != NFX_OK) {
				printf("Getting idmap recid from cluster db failed\n");
				rc = CMD_ERR_FAILED;
				goto return_free;
			}
			if (numRec == 0) {
				break;
			}

			for (idx = 0; idx < numRec - startRec; idx++) {
				if (cluster_getRecordDataFromList(idx,
											pRecList,
											CLUSTER_IDMAP_BUFF_SIZE,
											&dataLen,
											ruleBufp ) != NFX_OK) {
					printf("Getting idmap recid from cluster db failed\n");
					rc = CMD_ERR_FAILED;
					goto return_free;
				}

				ruleBufp[dataLen] = '\0';
				printf("%-5s  %-3d  %s\n", typeStr, idx+1, ruleBufp);
			}
			if (pageNo) {
				break;
			}
		}
    }

return_free:
	free(ruleBufp);
return_free_reclist:
	free(pRecList);

return_no_free:
    return rc;
}



void
install_idmap (priv_t myPriv, enum node_type node)
{
    struct cmd_option opt[] = {{CMD_OPT_PRIV, (void*)PRIV_SECURITY_ADMIN},
                               {CMD_OPT_DB, (void*)CLUSDB_VERSION},
                               {0, 0}};
    
/*
    Organizing this switch statment such that the higher priority commands
    are first allows us to fall through and pick up the lower priority
    ones at no extra cost.
 */
    switch (myPriv) {
        case diagPriv:
        case fullPriv:
            install_element_common_with_options (node, &delete_cmd, opt);
        case changePriv:
            install_element_w_priv (node, &notifyChange_cmd, PRIV_SECURITY_ADMIN);
        case addPriv:
            install_element_common_with_options (node, &add_cmd, opt);
        case viewPriv:
/*
    These commands are available in all modes
 */
            
            install_element (node, &show_cmd);
    }
}

--MP_u4bOGzT9BMtiAZ46A6s/fK4--
