Previous Topic: Authorization APINext Topic: Event API


Tunnel Service API

This section contains the following topics:

Tunnel Service API Overview

Develop a Custom Tunnel Service

Tunnel Service API Overview

The Tunnel Service API provides secure transfer of data between an agent and a shared library that supports the Tunnel Service.

When an agent sends a tunnel request to the Policy Server, the request contains:

The Policy Server initializes the appropriate service, invokes the requested function, and passes the data to the function. Once the service has performed its task, the Policy Server returns the results to the agent. The following graphic shows how the API is used in the tunnel service process:

Graphic showing how the API is used in the tunnel service process

Develop a Custom Tunnel Service

Each tunnel service is an instance of a shared library that supports the Tunnel Service API. To support a tunnel service, you must build a new shared library.

Install the shared library in one of the following locations:

Include File

To develop a tunnel service, include the SmApi.h header file:

#include "SmApi.h"

Function Summary

The shared library must provide the following functions as externally visible entry points:

Function

Description

SmQueryVersion()

Requests the Tunnel Service API version that the custom library is compliant with.

SmTunnelInit()

Initializes the tunnel service.

SmTunnelRelease()

Releases the tunnel service.

User-Defined Function

Calls the function that the tunnel agent is requesting.

Each entry point in the shared library must be defined according to specified syntax.

Note: If you are using Microsoft Visual Studio, export the function addresses to a modular definition file (.DEF) file. To export the function addresses, create a .DEF file, and in the export section of the .DEF file, list all of the tunnel service functions, described in the previous table. Once you have created the .DEF file, add it to the Microsoft Visual Studio project.

SmQueryVersion()

SiteMinder calls this function to request the Tunnel Service API version that the custom library is compliant with.

Syntax

int SM_EXTERN SmQueryVersion (
   const Sm_Api_Context_t* lpApiContext
);

Parameter

I/O

Description

lpApiContext

I

A pointer to the API context structure.

Returns

Returns the version number of the Tunnel Service API. Currently the versions supported are Sm_Api_Version_V4 and Sm_Api_Version_V4_1. Version constants are defined in SmApi.h.

SmTunnelInit()

SiteMinder calls this function so that a tunnel service can perform its own initialization procedure. This call is made once when the tunnel service is loaded for the first time. The information is cached for subsequent use.

Syntax

int SM_EXTERN SmTunnelInit (
   void**                     ppServiceHandle,
   const Sm_Api_Context_t*    lpApiContext,
   const int                  nBytesStatusBuf,
   char*                      lpszStatusBuf
);

Parameter

I/O

Description

ppServiceHandle

I

An internal pointer used by the tunnel service library.

lpApiContext

I

A pointer to the API context structure.

nBytesStatusBuf

O

Maximum size of the output status buffer.

lpszStatusBuf

O

Output buffer receives any status messages from the tunnel service.

Returns

Returns 0 if successful or -1 if unsuccessful.

SmTunnelRelease()

SiteMinder calls this function so that a tunnel service can perform its own rundown procedure. This call is made once when SiteMinder is shutting down.

Syntax

void SM_EXTERN SmTunnelRelease (
   void*                     pServiceHandle,
   const Sm_Api_Context_t*   lpApiContext
);

Parameter

I/O

Description

pServiceHandle

I

An internal pointer used by the tunnel service library.

lpApiContext

I

A pointer to the API context structure.

User-Defined Function

SiteMinder calls the function requested by the tunnel agent.

Syntax

int SM_EXTERN <func-spec> (
   void*                             pServiceHandle,
   const Sm_Api_Context_t*           lpApiContext,
   const Sm_Api_RequestContext_t*    lpReqContext,
   const Sm_Api_TunnelContext_t*     lpTunnelContext,
   const int                         nBytesInBuf,
   void*                             lpInBuf,
   const int                         nBytesOutBuf,
   void*                             lpOutBuf,
   const int                         nBytesStatusBuf,
   char*                             lpszStatusBuf
);

Parameter

I/O

Description

pServiceHandle

I

An internal pointer used by the tunnel service library.

lpApiContext

I

A pointer to the API context structure.

lpReqContext

I

A pointer to the API request structure.

lpTunnelContext

I

A pointer to the API tunnel context.

nBytesInBuf

I

Number of bytes in the input buffer.

lpInBuf

I

Input buffer containing information sent from the remote agent.

nBytesOutBuf

O

Maximum size of the output result buffer.

lpOutBuf

O

Output buffer to receive the result.

nBytesStatusBuf

O

Maximum size of the status buffer.

lpszStatusBuf

O

Status buffer to receive status.

Pass HTTP Headers and Cookies to Policy Server

You can add arbitrary custom key/value pairs to the current session to pass HTTP headers and cookies to the Policy Server. These key/value pairs are kept in the session store; they have the same lifetime as the session. The name/value pairs are stored in the Expiry Data Table in the session store database. There can be maximum 5 entries for a session. The Active Plugin code can use the UserContext structure (Sm_Api_UserContext_t* lpUserContext) to set and retrieve these name/value pairs by calling fSetProp and fGetProp respectively. To set the value, fSetProp is called with lpszPropName as SM_SESSIONVAR(<name>) and lpszValueBuf as the value. To retrieve the value, fGetProp is called with lpszPropName as SM_SESSIONVAR(<name>)/ SM_SESSIONVAR and the value/values is returned in lpszValueBuf.

Note the following:

Authorization Function Declarations

You must build the shared library with the proper entry points. Each entry point in the shared library represents one or more active expressions and must be defined according to the specified syntax.

Note: If you are using Microsoft Visual Studio, export the function addresses to a modular definition file (.DEF) file. To export the function addresses, create a .DEF file, and in the export section of the .DEF file, list the functions that you want to invoke from the Active Rule or Active Policy. After you have created the .DEF file, add it to the Microsoft Visual Studio project.

User-Defined Function

The Policy Server calls a user-defined function to perform a custom policy, rule, or response operation.

You can assign the function any name. Through the active expression that you define in the Administrative UI, you advise SiteMinder of the function name and the name of the shared library where the function resides.

Syntax

int SM_EXTERN <func-spec> (
   const Sm_Api_Context_t*          lpApiContext,
   const Sm_Api_UserContext_t*      lpUserContext,
   const Sm_Api_RequestContext_t*   lpReqContext,
   const char*                      lpszParam,
   const int                        nBytesOutBuf,
   char*                            lpszOutBuf,
   const int                        nBytesErrBuf,
   char*                            lpszErrBuf
);

Parameter

I/O

Description

lpApiContext

I

Pointer to the API context structure.

lpUserContext

I

Pointer to the user context structure.

lpReqContext

I

Pointer to the request context structure.

lpszParam

I

Pointer to the buffer containing the null-terminated parameter string specified in <Param-String>.

nBytesOutBuf

I

Maximum size of the output result buffer (4097 bytes).

lpszOutBuf

O

Output buffer for the result to send to SiteMinder.

nBytesErrBuf

I

Maximum size of the output error buffer (4097 bytes).

lpszErrBuf

O

Output buffer to receive error text. SiteMinder displays the error text in the debug log file.

Returns

SmQueryVersion()

The Policy Server calls this function to determine the Authorization API version that the custom library is compliant with.

Syntax

int SmQueryVersion (
   const Sm_Api_Context_t* lpApiContext
);

Parameter

I/O

Description

lpApiContext

I

A pointer to the API context structure.

Returns

Returns the version number of the Authorization API. Currently the version supported is Sm_Api_Version_V3. This constant is defined in SmApi.h.

Active Expression Examples

This samples provided in the following sections are located in:

sdk\samples\smazapi\smazapi.cpp

The syntax that precedes each sample, such as:

<@ lib="SmAzAPI" func="activeRule" param="" @>

is an example of the Generated Script that SiteMinder constructs in the SiteMinder Active Rule Editor, Active Policy Editor, or Active Response Attribute Editor dialog box from the information you provide in the dialog box.

To build sample active expressions for UNIX, use the makefile found in
<install_path>\sdk\samples\smazapi\makefile.

Example of an Active Rule

The example below returns true if the user has special access permission to view the realm. If the user has directory manager privileges, the user can view the realm.

<@ lib="SmAzAPI" func="activeRule" param="" @>
*************************************************************
int SM_EXTERN activeRule(
const Sm_Api_Context_t* lpApiContext,  
// the structure that provides API context
const Sm_Api_UserContext_t* lpUserContext,  
// the structure that provides user context
const Sm_Api_RequestContext_t* lpReqContext,   
// the structure that provides request context
const char* lpszParam, 
// the parameter string (null-terminated)
const int nBytesOutBuf,   
// the maximum size of the output buffer
char* lpszOutBuf, 
// the output buffer to hold the null-terminated result
const int nBytesErrBuf, 
// the maximum size of the error message buffer
char* lpszErrBuf)     
// the output buffer to hold the null-terminated error message
{
/* User Context is required to use the functions like fGetProp, fSetProp.. */
if(!lpUserContext->bIsUserContext)
   {
   strncpy (lpszErrBuf, "No User Context ", nBytesErrBuf);
   lpszErrBuf[nBytesErrBuf-1] = '\0';
   return -1;
   }
/*
// The DN to look for the attribute "uniquemember"
// If the user is listed as the member of the above attribute,
// it has directory manager privileges.
*/
char lpszDn[] = "cn=Directory Administrators,ou=Groups,o=airius.com";
char lpszDnvalue[256];
memset(lpszDnvalue, 0, sizeof(lpszDnvalue));
/*
// fGetDnProp function is used to retrieve an attribute value
// in a directory entry.
*/
int getResult = lpUserContext->fGetDnProp(
   lpUserContext->lpParam,
   lpszDn,
   "uniquemember",
   sizeof(lpszDnvalue),
   lpszDnvalue);
/*
// If no error occurs, fGenDnProp will return the length of the 
// buffer lpszDnvalue. Otherwise the function returns 0.
*/
if(getResult > 0)
   {

   /* Check to see if the user is present in the list. */
   if(strpbrk(lpszDnvalue, lpUserContext->lpszUserName) != NULL)
      {

      /* The result "true" is placed in the output buffer. */
      strncpy(lpszOutBuf, "true", nBytesOutBuf);
      lpszOutBuf[nBytesOutBuf-1] = '\0';
      return strlen(lpszOutBuf);
      }

      else

      {
      strncpy(lpszOutBuf, "false", nBytesOutBuf);
      lpszOutBuf[nBytesOutBuf-1] = '\0';
      return strlen(lpszOutBuf);
      }
   }
   
   else

   {
   strncpy(lpszErrBuf, "Failed to get attribute value for the DN ",
                        nBytesErrBuf);
   strncat( (lpszErrBuf + strlen(lpszErrBuf)), lpszDn,
             (nBytesErrBuf-strlen(lpszErrBuf)));
   lpszErrBuf[nBytesErrBuf-1] = '\0';
   return -1;
   }

/* everything failed.... */

return 0;

}
Example of an Active Response

This active response returns the common name (cn) of the user, if the user belongs to the organizational unit specified in the parameter (param) field of the active response expression.

<@ lib="SmAzAPI" func="activeResponse" param="Human Resources" @>
***********************************************************
int SM_EXTERN activeResponse(
const Sm_Api_Context_t*   lpApiContext,   
/* the structure that provides API context */
const Sm_Api_UserContext_t*  lpUserContext, 
/* the structure that provides user context */
const Sm_Api_RequestContext_t*  lpReqContext,   
/* the structure that provides request context */
const char* lpszParam,      
/* the parameter string (null-terminated) */
const int  nBytesOutBuf,   
/* the maximum size of the output buffer */
char*  lpszOutBuf,     
/* the output buffer to hold the null-terminated attribute value */
const int   nBytesErrBuf,   
/* the maximum size of the error message buffer */
char*   lpszErrBuf)     
/* the output buffer to hold the null-terminated error message */
{
memset(lpszOutBuf, 0, sizeof(lpszOutBuf));
if(!lpUserContext->bIsUserContext)
      {
      strncpy (lpszErrBuf, "No User Context ", nBytesErrBuf);
      lpszErrBuf[nBytesErrBuf-1] = '\0';
      return -1;
      }
/* Store all the organizational units to which the user belongs. */
char lpszOrgUnit[30];
memset(lpszOrgUnit, 0, sizeof(lpszOrgUnit));
/* store the common name of the user. */
char lpszCN[30];
memset(lpszCN, 0, sizeof(lpszCN));
/* Check to see if a parameter is requested. */
if(lpszParam == NULL || strlen(lpszParam) == 0) 
   {
   strncpy (lpszErrBuf, "Organizational unit is not entered ",
            nBytesErrBuf);
   lpszErrBuf[nBytesErrBuf-1] = '\0';
   return -1;
   }
/* Get all the organization units to which the user belongs. */
int getResult = lpUserContext->fGetProp (
   lpUserContext->lpParam,
   "ou",              /* Attribute name */
   sizeof (lpszOrgUnit), lpszOrgUnit);
if (getResult < 0)
   {
   strncpy (lpszErrBuf, 
        "Failed to get organization unit for the user's profile ",
        nBytesErrBuf);
   strncat( (lpszErrBuf + strlen(lpszErrBuf)), 
            lpUserContext->lpszUserName, 
            (nBytesErrBuf-strlen(lpszErrBuf)));
   lpszErrBuf[nBytesErrBuf-1] = '\0';
   return -1;
   }
    else
    {
/* Check if the user belongs to the organization unit that is requested. */
   if(strstr(lpszOrgUnit, lpszParam) != NULL)
      {
      if((lpUserContext->fGetProp(lpUserContext->lpParam,
           "cn",sizeof(lpszCN),lpszCN)) > 0)
         {
         strncpy(lpszOutBuf, lpszCN, nBytesOutBuf);
         lpszOutBuf[nBytesOutBuf-1] = '\0';
         return strlen(lpszOutBuf);
         } /* end of fGetProp */
         else
         {
         strncpy (lpszErrBuf, 
          "Failed to get user common name from user's profile attribute ",
           nBytesErrBuf);
         strncat( (lpszErrBuf + strlen(lpszErrBuf)),
                    lpUserContext->lpszUserName, 
                    (nBytesErrBuf-strlen(lpszErrBuf)));
         lpszErrBuf[nBytesErrBuf-1] = '\0';
         return -1;
         }
        } /* end of strstr */
        else
        {
      strncpy (lpszErrBuf, 
       "The user does not belong to the requested organizational unit ", 
        nBytesErrBuf);
      lpszErrBuf[nBytesErrBuf-1] = '\0';
      return -1;
      }
   }
    /* everything failed.... */
    return 0;
 }
#ifndef _WIN32
}

#endif