DB2 security, Part 10: Deploy customized security plug-ins in DB2 9

Security plug-ins bring new versatility to your database security setup in IBM® DB2® 9. Read this article to determine what should be tested before deploying your own customized security plug-ins. Accompanying this article, there is a security plug-in loader program for AIX® 64 bit, Linux® AMD 64 bit, Linux AMD 32 bit, Linux IA 32 bit, and Sun Solaris 64 bit operating system platforms. This loader enables the reader to perform sanity testing on the security plug-in code before hooking up with DB2 for further testing. This article also discusses how to take advantage of the new enhancements to the security plug-in infrastructure in DB2 9.

Kevin Yeung-Kuen See (see@ca.ibm.com), Software Developer, IBM

Kevin See photoKevin Yeung-Kuen See, CISSP, has been a software developer at the IBM Toronto Laboratory for the past decade. His experience includes working on the DB2 Security Development team and the DB2 SQL and Catalog Development team. He received a Masters of Mathematics in Computer Science (specializing in software engineering) from University of Waterloo and a Bachelor of Computer Science from Acadia University. He is an IBM Certified Solutions Developer for XML and Related Technologies and a DB2 Certified Solutions Expert (DBA for OS390, DBA for Linux, Unix, and Windows, Advanced DBA for Linux, Unix, and Windows, and DB2 Family Application Development). He is also an ISC2 Certified Information Systems Security Professional (CISSP). He has written a few IBM developerWorks articles on the topic of DB2 security and is co-authoring an upcoming retail book titled "Understanding DB2 9 Security." In his spare time, he enjoys hiking, learning something new, and trying to figure out the world according to Justin, his toddler son.



Yung Chung (ychung@ca.ibm.com), Software Developer, IBM

Yung Chung is a Software Developer at the IBM Toronto Lab working in the DB2 Continuing Engineering team. Prior to that, he worked on the DB2 UNIX Development team. Yung received a Bachelor of Science degree from York University and is is an IBM Certified Solutions Expert (DBA for Linux/UNIX/Windows).



19 October 2006

Introduction

In part 2 of this series, DB2 security plug-ins were introduced, as well as the method in which DB2 security is implemented, and a list of relevant detailed information about security plug-ins. In part 6 of this series, the DB2 shipped Kerberos security plug-ins were introduced as well as how to deploy Kerberos authentication using this plug-in. This article explains what the plug-in writer or database administrator should test before deploying the customized security plug-ins to the DB2 system.

Authorization in DB2 is based on two things:

  • The effective database authorization ID (authid) of the external user performing a particular task
  • The membership of that user in particular groups

Before knowing if a user is authorized to do a particular operation, DB2 must be able to know the effective database authorization ID of the external user, and in which groups that user belongs. In order to find the effective database authorization ID, you need to ensure that the external user is who they say they are, and then map their external user ID to an internal DB2 authorization ID. The process of doing this is referred to as authentication. DB2 does not have its own mechanism for maintaining user IDs and passwords, or user ID group memberships.

What does a security plug-in do?

There are two events that require the use of either (client-side or server-side) an authentication plug-in or group membership look-up plug-in:

  • During the connection or instance attachment
  • During instance-level operation authorization

Instance-level operation is any operation that has to due with the maintenance of a DB2 instance. Some typical examples of instance-level operations are update database manager, configuration parameter, and start database manager.

Take a look at instance-level operations first. Most instance-level operation commands do not accept user IDs or passwords as part of the input. In this case, you have to employ the client-side authentication plug-in (also known as the client auth plug-in) to find out who is the current logon user that is issuing the command. (This is what is referred to as getting a default login context. A login context can be a user ID/password pair or a Generic Security Services API [GSS-API] credential such as a Kerberos ticket). Once the user's identity is obtained, the DB2 group membership lookup plug-in (also known as the group plug-in) is used to generate a list of group authorization IDs for the user.

During a connection establishment or instance attachment, user IDs and passwords are optional. If the user chooses to opt out of specifying the user ID and password, DB2 employs the client auth plug-in to get the default login context. Then, the login context is sent to the server for obtaining group authorization IDs for the user. If the user chooses to specify a user ID and password, DB2 performs the following steps if the authentication type database manager configuration parameter is not specified as CLIENT:

Table 1. Flow of information for authentication other than CLIENT
ClientFlow of information (if applicable)Server
(Client auth plug-in)
Remap user ID, password, and namespace if the db2secRemapUserid is implemented and the authentication plug-in is user ID/password based. Note that this process also applies to the default login context case.
Sent the login context to the server. Login context ->Server received the login context.
(Server auth plug-in)
Validate the login context (validate the user ID and password or the GSS-API credential such as Kerberos ticket) and obtained the authorization ID for the user.
Obtained the group authorization ID for the user using the group plug-in on the server.

If the authentication type is specified as CLIENT authentication on the database server, the following step occurs:

Table 2. Flow of information for CLIENT authentication
ClientFlow of information (if applicable)Server
(Client auth plug-in)
Remap user ID, password, and namespace if the db2secRemapUserid is implemented and the authentication plug-in is user ID/password based. Note that this process also applies to the default login context case.
(Client auth plug-in)
Validate the login context (validate the user ID and password or the GSS-API credential such as Kerberos ticket) and obtained the authorization ID for the user.
Sent the user ID to the server.user ID ->(Server auth plug-in) Server received user ID and obtained the authorization ID for the user.
Obtained the group authorization ID for the user using the group plug-in on the server.

Suggested minimum sanity testing

Based on the duties of the security plug-in that was described in the previous section, it is suggested that the security plug-in should go through the following testing at a minimum:

  1. Using an unauthorized user, attempt to perform instance-level operations such as get the database manager configuration parameter. This should fail.
  2. Using an authorized user, attempt to perform instance-level operations. This should succeed.
  3. Using a valid user ID and password, establish a connection to a database and attempt to exercise the privilege granted to one of the group authorization IDs. This should succeed.
  4. Attempt to use either an invalid user ID or an invalid password to connect. This should fail.
  5. Attempt to connect without specifying a user ID and password. This should only work if the client and the server are on the same machine, and no special restriction logic is implemented in the customized security plug-ins. This ensures the right login user credential is returned by the customized security plug-in to DB2.
  6. If you are implementing customized group plug-ins, make sure your db2secGetGroupForUser API understands authorization ID and is always uppercased, despite the fact that your customized authentication plug-in might have returned an authorization ID that is of mixed case or lower case.

Security plug-in loader

The security plug-in loader program allows you to simulate DB2s responses to the suggested testing above. This could be very useful if you want to figure out whether a particular problem is due to code within your plug-in or on the DB2 side.

Program inputs are:

  • -c option: The fully qualified path and the plug-in name for the client-side auth plug-in.
  • -s option: The fully qualified path and the plug-in name for the server-side auth plug-in.
  • -g option: The fully qualified path and the plug-in name for the group plug-in.
  • -u option: User ID.
  • -p option: Password. (For GSS-API or Kerberos, this is the password that is used to get the user credential.)
  • -d option: Database name.
  • -n option: New password.
  • -a option: User authorization ID.

At the launch or execution time of the loader, all three specified security plug-ins (client auth plug-in, server auth plug-in, and group plug-in) are loaded as needed and the type of authentication plug-in (such as user ID/password-based, Kerberos-based, or GSS-API-based) is determined. The initialization functions for each plug-in are called and all the function pointers for each plug-in are retrieved.

Based on the combination of the options you specified, it performs one of the following four types of testing for you.

For simplicity, this loader does not support testing of client authentication, and it does not provide the get Client connection details callback functions to your customized plug-in (such as, db2secGetConDetails). The db2secLogMessage is provided to the plug-in, but the output is directed to your standard output (screen).

The following four testing functionalities are provided by the loader to simulate the usage of the security plug-in on a DB2 environment calling the exact same sequence of APIs.

Testing functionality 1

Establish a connection with the given user ID and password, and validate the password or credentials. The output is the authid and the group authids list.

  1. The following is the API calling sequence if a Kerberos or GSS-API-based authentication plug-in is in use:
    • Client plug-in: db2secProcessServerPrincipalName
    • Client plug-in: db2secGenerateInitialCred
    • Client plug-in: gss_init_sec_context
    • Server plug-in: gss_accept_sec_context

    There is a loop between the client-side API: gss_init_sec_context and the server-side API: gss_accept_sec_context, until one side returns GSS_S_COMPLETE. If more tokens are expected from the other side, the API should return GSS_S_CONTINUE_NEEDED.

    • Client plug-in: gss_release_buffer, gss_release_name, gss_release_cred, db2secFreeInitInfo, gss_delete_sec_context
    • Server plug-in: gss_release_buffer, db2secGetAuthIDs
    • Group plug-in: db2secGetGroupForUser
    • Client plug-in: db2secFreeToken
    • Server plug-in: gss_delete_sec_context
    • Group plug-in: db2secFreeGroupListMemory
    Figure 1. API calling sequence with a Kerberos or GSS-API-based authentication plug-in
    API calling sequence with a Kerberos or GSS-API-based authentication plug-in
  2. The following is the API calling sequence if a user ID/password-based authentication plug-in is in use:
    • Client plug-in: db2secRemapUserid if it is optionally implemented
    • Server plug-in: db2secValidatePassword, db2secGetAuthIDs
    • Group plug-in: db2secGetGroupForUser
    • Server plug-in: db2secFreeToken
    • Group plug-in: db2secFreeGroupListMemory
    Figure 2. API calling sequence with a user ID/password-based authentication plug-in
    API calling sequence with a user ID/password-based authentication plug-in

Testing functionality 2

Establish a connection without providing a user ID and password (default login context). The output is the authid and group authids list.

  1. The following is the API calling sequence if a Kerberos or GSS-API-based authentication plug-in is in use:
    • Client plug-in: db2secGetDefaultLoginContext
    • Client plug-in: db2secProcessServerPrincipalName
    • Client plug-in: gss_init_sec_context
    • Server plug-in: gss_accept_sec_context

    There is a loop between the client-side API: gss_init_sec_context and the server side API: gss_accept_sec_context, until one side returns GSS_S_COMPLETE. If more tokens are expected from the other side, the API should return GSS_S_CONTINUE_NEEDED.

    • Client plug-in: gss_release_buffer, gss_release_name, gss_delete_sec_context
    • Server plug-in: gss_release_buffer, db2secGetAuthIDs
    • Group plug-in: db2secGetGroupForUser
    • Client plug-in: db2secFreeToken
    • Server plug-in: gss_delete_sec_context
    • Group plug-in: db2secFreeGroupListMemory
    Figure 3. API calling sequence with a Kerberos or GSS-API-based authentication plug-in
    API calling sequence with a Kerberos or GSS-API-based authentication plug-in
  2. The following is the API calling sequence if a user ID/password-based authentication plug-in is in use:
    • Client plug-in: db2secGetDefaultLoginContext, db2secFreeToken
    • Server plug-in: db2secGetAuthIDs
    • Group plug-in: db2secGetGroupForUser
    • Server plug-in: db2secFreeToken
    • Group plug-in: db2secFreeGroupListMemory
    Figure 4. API calling sequence with a user ID/password-based authentication plug-in
    API calling sequence with a user ID/password-based authentication plug-in

Testing functionality 3

Given a user authorization ID, the output is the group authids list.

The following is the API calling sequence:

  • Group plug-in: db2secGetGroupsForUser
Figure 5. API calling sequence
API calling sequence

Testing functionality 4

Simulate the testing of the local authorization for an instance-level operation (without the user ID and password). The output is the group authids list.

The following is the API calling sequence:

  • Client plug-in: db2secGetDefaultLoginContext
  • Group plug-in: db2secGetGroupForUser
  • Client plug-in: db2secFreeToken
  • Group plug-in: db2secFreeGroupListMemory
Figure 6. API calling sequence
API calling sequence

Enhancements to DB2 security plug-ins in DB2 9

In DB2 9, there have been numerous enhancements to the DB2 security plug-in infrastructure, including the shipping of the Lightweight Directory Access Protocol (LDAP)-based authentication plug-in, the shipping of the LDAP-based group membership look-up plug-in, and enhancement to the client connection details to include support for TCP/IP Version 6 and the client machine operating system platform information.

You can download the IBM supported LDAP-based authentication plug-in and group membership look-up plug-in from DB2 LDAP Authentication Plugins.

If you have implemented a connection restriction through a TCP/IP address (An example of how to do so is found in the "Steps to test connection restriction ability of the plug-in" section in part 2 of this series.), and your company is moving toward implementing TCP/IP Version 6, you need to modify your security plug-in to handle it.

First of all, you need to start using either Version 2 or 3 of the connection details structure listed below (extracted from IBM-shipped header file db2secPlugin.h). The difference between Version 2 and 3 is that the Version 3 also gives you the client machine operating system platform.

Listing 1. New version of client connection details structure
typedef struct db2sec_con_details_2
{
  db2int32  clientProtocol;     /* See SQL_PROTOCOL_ in sqlenv.h */
  db2Uint32 clientIPAddress;    /* Set if protocol is TCPIP4     */
  db2Uint32 connect_info_bitmap;
  db2int32  dbnameLen;
  char dbname[DB2SEC_MAX_DBNAME_LENGTH + 1];
  db2Uint32 clientIP6Address[4];/* Set if protocol is TCPIP6     */  
} db2sec_con_details_2;

typedef struct db2sec_con_details_3
{
  db2int32  clientProtocol;     /* See SQL_PROTOCOL_ in sqlenv.h */
  db2Uint32 clientIPAddress;    /* Set if protocol is TCPIP4     */
  db2Uint32 connect_info_bitmap;
  db2int32  dbnameLen;
  char dbname[DB2SEC_MAX_DBNAME_LENGTH + 1];
  db2Uint32 clientIP6Address[4];/* Set if protocol is TCPIP6     */  
  db2Uint32 clientPlatform;     /* SQLM_PLATFORM_* from sqlmon.h */
  db2Uint32 _reserved[16];
} db2sec_con_details_3;

Then, use DB2SEC_CON_DETAILS_VERSION_2 or DB2SEC_CON_DETAILS_VERSION_3 instead of using DB2SEC_API_VERSION_1 or the number 1 as suggested by the DB2 V8.2 documentation when you are calling the callback function. For example, assume that you want to use the Version 3 of the information; you can do the following callback inside your plug-in:

         struct db2sec_con_details_3  con_struct3;
         rc = (getConDetails_fn)(DB2SEC_CON_DETAILS_VERSION_3,  &con_struct3);

Since rolling out TCP/IP Version 6 over the entire organization can be a long process, it is possible that DB2 will encounter some clients that are still using the TCP/IP Version 4 and other clients that are switched to TCP/IP Version 6. To help the customer to distinguish this client, the clientProtocol field of the structure is now able to return either SQL_PROTOCOL_TCPIP4 or SQL_PROTOCOL_TCPIP6 to indicate whether the client is using Version 4 or Version 6 of the TCP/IP protocol.

If you need to find out the operating system of the client machine, you can check the integer value returned by DB2 through the callback function in the field clientPlatform. The mapping of the integer to the corresponding platform are (extracted from IBM shipped header file sqlmon.h):

#define SQLM_PLATFORM_UNKNOWN         0         /* Unknown platform           */
#define SQLM_PLATFORM_OS2             1         /* OS/2                       */ 
#define SQLM_PLATFORM_DOS             2         /* DOS                        */ 
#define SQLM_PLATFORM_WINDOWS         3         /* Windows                    */ 
#define SQLM_PLATFORM_AIX             4         /* AIX                        */ 
#define SQLM_PLATFORM_NT              5         /* NT                         */ 
#define SQLM_PLATFORM_HP              6         /* HP                         */
#define SQLM_PLATFORM_SUN             7         /* Sun                        */
#define SQLM_PLATFORM_MVS_DRDA        8         /* MVS (client via DRDA)      */
#define SQLM_PLATFORM_AS400_DRDA      9         /* AS400 (client via DRDA)    */
#define SQLM_PLATFORM_VM_DRDA        10         /* VM (client via DRDA)       */
#define SQLM_PLATFORM_VSE_DRDA       11         /* VSE (client via DRDA)      */
#define SQLM_PLATFORM_UNKNOWN_DRDA   12         /* Unknown DRDA Client        */
#define SQLM_PLATFORM_SNI            13         /* Siemens Nixdorf            */
#define SQLM_PLATFORM_MAC            14         /* Macintosh Client           */
#define SQLM_PLATFORM_WINDOWS95      15         /* Windows 95                 */
#define SQLM_PLATFORM_SCO            16         /* SCO                        */
#define SQLM_PLATFORM_SGI            17         /* Silicon Graphic            */
#define SQLM_PLATFORM_LINUX          18         /* Linux                      */
#define SQLM_PLATFORM_DYNIX          19         /* DYNIX/ptx                  */
#define SQLM_PLATFORM_AIX64          20         /* AIX 64 bit                 */
#define SQLM_PLATFORM_SUN64          21         /* Sun 64 bit                 */
#define SQLM_PLATFORM_HP64           22         /* HP 64 bit                  */
#define SQLM_PLATFORM_NT64           23         /* NT 64 bit                  */
#define SQLM_PLATFORM_LINUX390       24         /* Linux for S/390            */ 
#define SQLM_PLATFORM_LINUXZ64       25         /* Linux for z900             */ 
#define SQLM_PLATFORM_LINUXIA64      26         /* Linux for IA64             */
#define SQLM_PLATFORM_LINUXPPC       27         /* Linux for PPC              */
#define SQLM_PLATFORM_LINUXPPC64     28         /* Linux for PPC64            */
#define SQLM_PLATFORM_OS390          29         /* OS/390 Tools (CC, DW)      */
#define SQLM_PLATFORM_LINUXX8664     30         /* Linux for x86-64           */
#define SQLM_PLATFORM_HPIA           31         /* HP-UX Itanium 32bit        */ 
#define SQLM_PLATFORM_HPIA64         32         /* HP-UX Itanium 64bit        */

In the sample connection restriction code in part 2 of the series, gethostname and gethostbyname are used to the TCP/IP address of the database server machine. The following is an extract of code from the sample where it is blocking a loopback connection on the database server:

Listing 2. Connection restriction code from part 2 of the series
         /* If the connection is not local */
         if (!(con_struct.connect_info_bitmap & DB2SEC_CONNECTION_ISLOCAL))
         {
            struct hostent*   hostinfo;
            char              hostname[256];
            int*              firstaddr;

            /* Get the address of the machine restricted */
            gethostname(hostname, sizeof(hostname));
            hostinfo = gethostbyname(hostname);
            firstaddr = (int *)*(hostinfo->h_addr_list);

            /* If the client IP address is the restricted one */
            if (*firstaddr == con_struct.clientIPAddress)
            {
               /* We won't allow behavoir to connect through this IP address */
               if (0 == strcmp(userid, "beauvoir"))
                  return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
            }
         }

You need to modify to the following in order to work with Version 6 of the TCP/IP protocol:

Listing 3. Connection restriction code that works with IP V6
            if (!(con_struct3.connect_info_bitmap & DB2SEC_CONNECTION_ISLOCAL))
            {
               struct addrinfo* pAddr;
               /* find the local IP address to compare it with the one retrieved */
               
               if ((con_struct3.clientProtocol == SQL_PROTOCOL_TCPIP6) &&         
                (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)con_struct3.clientIP6Address)))
               {
              /* Comment out the following line of code if your database server is not */
                  /* running on MS Windows */
                  aiHints.ai_flags = AI_ALL | AI_V4MAPPED;
               }
               else
               {
                  aiHints.ai_flags = AI_PASSIVE; 
               }             
               aiHints.ai_family   = (con_struct3.clientProtocol == SQL_PROTOCOL_TCPIP6)? 
                                                    AF_INET6 : AF_INET; 
               aiHints.ai_socktype = SOCK_STREAM;
               aiHints.ai_protocol = IPPROTO_TCP;
               err = getaddrinfo(hostname, NULL, &aiHints, &aiList);
               if (err)
               {
                  Print("getaddrinfo error: %d\n", err);
                  return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
               }      
               /* compare the IPs */
               if (SQL_PROTOCOL_TCPIP6 == con_struct3.clientProtocol)
               {
                  pAddr = aiList;
                  while (pAddr)
                  {
                     struct sockaddr_in6* s = (struct sockaddr_in6*)pAddr->ai_addr;
                     struct in6_addr *src = (struct in6_addr*)&s->sin6_addr;
                     struct in6_addr *dst = 
                              (struct in6_addr*)&con_struct3.clientIP6Address; 
                     /* check if address verified is the same format as the address 
                      * sent by the client: compare only IPv6 format address with 
                      * IPv6 ones or IPv6 mapped IPv4 with the same type */
                     if ((*(db2Uint32*)(&s->sin6_addr.s6_addr[0]) == 
                               con_struct3.clientIP6Address[0]) &&
                         (*(db2Uint32*)(&s->sin6_addr.s6_addr[4]) == 
                              con_struct3.clientIP6Address[1]) &&
                         (*(db2Uint32*)(&s->sin6_addr.s6_addr[8]) == 
                              con_struct3.clientIP6Address[2]) &&
                         (*(db2Uint32*)(&s->sin6_addr.s6_addr[12])== 
                              con_struct3.clientIP6Address[3]))
                     {
                        /* don't allow beauvoir to connect through this ip address */
                        if (0 == strcmp(userid, "beauvoir"))
                        {
                           return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;          
 
                        }
                        else
                        {
                           break;
                        }
                     }
                     pAddr = pAddr->ai_next;
                  } /* while (pAddr) */
               }
               else /* This else clause is need if you have a mix v4 and v6 environment */
               {
                  /* TCPIP4 */
                  struct sockaddr_in* s = (struct sockaddr_in*)aiList->ai_addr;
                  if (s->sin_addr.s_addr == con_struct3.clientIPAddress)
                  {
                     /* don't allow beauvoir to connect through this ip address */
                     if (0 == strcmp(userid, "beauvoir"))
                        return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
                  }
               }
               freeaddrinfo(aiList);
            }

Conclusion

This article provided you the enhancement information for the DB2 security plug-in in DB2 9, and explained in detail the duties of the security plug-ins. The article also suggested a list of minimum sanity testing based on these duties. You should now understand how to use the security plug-in loader, which is found in the Download section, to test customized security plug-ins.


Download

DescriptionNameSize
Plug-in loader programloader.zip58KB

Resources

Learn

Get products and technologies

  • DB2 LDAP Authentication Plugins: Download the IBM supported LDAP-based authentication plug-in and group membership look-up plug-in.
  • Download a free trial version of DB2 Enterprise 9.
  • Now you can use DB2 for free. Download DB2 Express-C, a no-charge version of DB2 Express Edition for the community that offers the same core data features as DB2 Express Edition and provides a solid base to build and deploy applications.
  • Download IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
  • Build your next development project with IBM trial software, available for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management
ArticleID=169259
ArticleTitle=DB2 security, Part 10: Deploy customized security plug-ins in DB2 9
publish-date=10192006