/*!
  @file           RTE_UNIXAuthenticate.cpp
  @author         JoergM
  @brief          DBM RunTime: User Authentification

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
*/

#include "RunTime/RTE_UNIXAuthenticate.hpp"
#include "RunTime/RTE_IniFileHandling.h"
#include "RunTime/RTE_saveUNIXcalls.h"
#include "RunTime/System/RTESys_IO.h"
#include "RunTime/RTE_MessageList.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "SAPDBCommon/SAPDB_Names.h"
#include "heo01.h"
#include "SAPDBCommon/SAPDB_sprintf.h"
#include "geo28.h"
#include "RunTime/Synchronisation/RTESync_Spinlock.hpp"

#include <unistd.h>
/* this .... is needed due to corrupted header file grp.h on tru64... */
#if defined(OSF1)
#  ifdef _XOPEN_SOURCE_EXTENDED
#    undef _XOPEN_SOURCE_EXTENDED
#      include <grp.h>
#    define _XOPEN_SOURCE_EXTENDED
#  else
#    include <grp.h>
#  endif
#else
#  include <grp.h>
#endif
#include <sys/wait.h>

#ifndef NO_CRYPT
#ifndef AIX
/* on AIX this produces a confilct with stdlib.h definition of setkey.... */
#include <crypt.h>
#endif /* AIX */
#endif /* NO_CRYPT */

#include <pwd.h>

/*--------------------*/

static RTESync_Spinlock lock;   // to get user/group id by name, the system calls getpwnam()
                                // and getgrnam() are used here. They are not reentrant, so
                                // to avoid race conditions, these routines are called in a
                                // locked scope. This is the spinlock used for the locked scope.
                                // PTS 1129679
SAPDB_Bool
RTE_GetUserIdFromUsername(SAPDB_Char const *Username,
                          SAPDB_Int4       &userId,
                          SAPDBErr_MessageList &errList)
{
    if ( Username )
    {
        RTESync_LockedScope scope(lock);
        struct passwd *pwEntry = getpwnam (Username);

        if ( ! pwEntry )
        {
            errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                           RTEERR_USER_UNKNOWN,
                                           Username);
            return false;
        }

        userId = (SAPDB_Int4)(pwEntry->pw_uid);
        return true;
    }
    else
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_USER_UNKNOWN,
                                       "no user given");
        return false;
    }
}

/*--------------------*/

SAPDB_Bool
RTE_GetUserAndPrimaryGroupIdFromUsername( SAPDB_Char const     *Username,
                                          SAPDB_Int4           &userId,
                                          SAPDB_Int4           &groupid,
                                          SAPDBErr_MessageList &errList)
{
    if ( Username )
    {
        RTESync_LockedScope scope(lock);
        struct passwd *pwEntry = getpwnam (Username);

        if ( ! pwEntry )
        {
            errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                           RTEERR_USER_UNKNOWN,
                                           Username);
            return false;
        }

        userId = (SAPDB_Int4)(pwEntry->pw_uid);
        groupid = (SAPDB_Int4)(pwEntry->pw_gid);
        return true;
    }
    else
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_USER_UNKNOWN,
                                       "no user given");
        return false;
    }
}

/*--------------------*/

SAPDB_Bool
RTE_GetUsernameFromUserId(SAPDB_Int4  userId,
                          SAPDB_Char *UsernameBuffer,
                          SAPDB_Int4  UsernameBufferSize,
                          SAPDBErr_MessageList &errList)
{
    struct passwd *pwEntry = getpwuid ((uid_t)userId);

    SAPDBERR_ASSERT_STATE(UsernameBuffer != 0);
    SAPDBERR_ASSERT_STATE(UsernameBufferSize > 0);

    if ( ! pwEntry )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_USERID_UNKNOWN,
                                       SAPDB_ToString(userId) );
        return false;
    }

    if ( strlen(pwEntry->pw_name) >= UsernameBufferSize )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_USERNAME_TOO_LONG,
                                       SAPDB_ToString(userId),
                                       pwEntry->pw_name);
        return false;
    }

    strcpy(UsernameBuffer, pwEntry->pw_name);
    return true;
}

/*--------------------*/

SAPDB_Bool
RTE_GetGroupIdFromGroupname( SAPDB_Char const *Groupname,
                             SAPDB_Int4       &groupid,
                             SAPDBErr_MessageList &errList)
{
    if ( Groupname )
    {
        RTESync_LockedScope scope(lock);
        struct group *grEntry = getgrnam (Groupname);

        if ( ! grEntry )
        {
            errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                           RTEERR_GROUP_UNKNOWN,
                                           Groupname);
            return false;
        }

        groupid = (SAPDB_Int4)(grEntry->gr_gid);
        return true;
    }
    else
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_GROUP_UNKNOWN,
                                       "no group given");
        return false;
    }
}

/*--------------------*/

SAPDB_Bool
RTE_GetGroupnameFromGroupId(SAPDB_Int4  groupid,
                            SAPDB_Char *GroupnameBuffer,
                            SAPDB_Int4  GroupnameBufferSize,
                            SAPDBErr_MessageList &errList)
{
    struct group *grEntry = getgrgid ((gid_t)groupid);

    SAPDBERR_ASSERT_STATE(GroupnameBuffer != 0);
    SAPDBERR_ASSERT_STATE(GroupnameBufferSize > 0);

    if ( ! grEntry )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_GROUPID_UNKNOWN,
                                       SAPDB_ToString(groupid) );
        return false;
    }

    if ( strlen(grEntry->gr_name) >= GroupnameBufferSize )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_GROUPNAME_TOO_LONG,
                                       SAPDB_ToString(groupid),
                                       grEntry->gr_name);
        return false;
    }

    strcpy(GroupnameBuffer, grEntry->gr_name);
    return true;
}

/*------------------------------*/

SAPDB_Bool
RTE_SetUserAndGroupId(SAPDB_Int4 userId,
                      SAPDB_Int4 groupId,
                      SAPDBErr_MessageList &errList)
{
    RTE_SystemRc rc;
    RTESys_ErrorMessage spaceToFill;
    SAPDB_Char UsernameBuffer[256];

    if ( !RTE_GetUsernameFromUserId( (SAPDB_Int4)userId,
                                     UsernameBuffer,
                                     (SAPDB_Int4)sizeof(UsernameBuffer),
                                     errList) )
    {
        return false;
    }

    /* root user must become effectiv root user before it can set to 'any' user/group combination! */
    if ( RTE_save_getuid() == 0 )
    {
        if ( RTE_save_setuid(0) )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETUID_FAILED,
                                            "for effective id 0",
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }
    }

    if ( RTE_save_geteuid() == 0 )
    {
        /* effective user is superuser */
        if ( RTE_save_setgid(groupId) )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETGID_FAILED,
                                            SAPDB_ToString(groupId),
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }

        if ( initgroups(&UsernameBuffer[0], groupId) )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETGID_FAILED,
                                            "initgroups failed",
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }

        if ( RTE_save_setuid(userId) )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETUID_FAILED,
                                            SAPDB_ToString(userId),
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }
    }
    else
    {
        /* effective user is no superuser */
        if ( RTE_save_setregid(groupId, groupId) )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETGID_FAILED,
                                            SAPDB_ToString(groupId),
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }

        if ( 
         RTE_save_setreuid(userId, userId)
#if defined(HPUX) || defined(OSF1) || defined(AIX)
      /* some platform do not allow non authorized users to set real user id */
      /* but these at least do not switch back to real user in 'system(command)' calls */
      && RTE_save_setreuid(    -1, userId)
#endif
       )
        {
            rc = RTESys_GetLastError();
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_SETUID_FAILED,
                                            SAPDB_ToString(userId),
                                            RTESys_StrError(rc, spaceToFill) );
            return false;
        }
    }

    return true;
}

/*---------------------------------*/

SAPDB_Bool
RTE_SetSapdbOwnerAndGroupId(SAPDBErr_MessageList &errList)
{
    SAPDB_Int4 userId;
    SAPDB_Int4 groupId;

    if ( !RTE_GetDefaultSapdbUserAndGroupIds( userId,
                                              groupId,
                                              errList ) )
    {
        return false;
    }

    return RTE_SetUserAndGroupId( userId,
                                  groupId,
                                  errList );
}

/*---------------------------------*/

void
RTE_GetEffectivUserIdAndGroupId(SAPDB_Int4 &userId, SAPDB_Int4 &groupId)
{
    userId = (SAPDB_Int4)RTE_save_geteuid(); 
    groupId = (SAPDB_Int4)RTE_save_getegid(); 
}

/*---------------------------------*/

void
RTE_GetRealUserIdAndGroupId(SAPDB_Int4 &userId, SAPDB_Int4 &groupId)
{
    userId = (SAPDB_Int4)RTE_save_getuid(); 
    groupId = (SAPDB_Int4)RTE_save_getgid(); 
}

/*---------------------------------*/

#define SUBPATH_TO_KERNEL_EXECUTABLE "/pgm/kernel"

SAPDB_Bool
RTE_IsSapdbOwnerOrRoot(SAPDBErr_MessageList &errList)
{
    if ( geteuid() == (uid_t)0 )
    {
        return true;
    }

    SAPDB_Char UsernameBuffer[256];
    SAPDB_Char OwnernameBuffer[256];

    if ( !RTE_GetUsernameFromUserId( (SAPDB_Int4)geteuid(),
                                     UsernameBuffer,
                                     (SAPDB_Int4)sizeof(UsernameBuffer),
                                     errList) )
    {
        return false;
    }

    RTE_IniFileResult  ok;
    RTE_IniFileErrtext errtext;
    RTE_GetInstallationConfigString( SAPDB_SAPDBOWNER_KEY, 
                                     OwnernameBuffer, 
                                     (SAPDB_Int4)sizeof(OwnernameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBOWNER_KEY,
                                        errtext
                                      );
        return false;
    }

    SAPDB_Int iCheck;
    for ( iCheck = 0; UsernameBuffer[iCheck] != 0; ++iCheck )
    {
        if ( toupper(UsernameBuffer[iCheck]) != toupper(OwnernameBuffer[iCheck]) )
        {
            break;
        }
    }

    if ( toupper(UsernameBuffer[iCheck]) != toupper(OwnernameBuffer[iCheck]) )
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_OWNERNAME_MISMATCH,
                                        UsernameBuffer,
                                        OwnernameBuffer
                                      );
        return false;
    }

    return true;
}

/*--------------------------*/

SAPDB_Bool
RTE_GetDefaultSapdbUserAndGroupIds(SAPDB_Int4 &userId,
                                   SAPDB_Int4 &groupId,
                                   SAPDBErr_MessageList &errList)
{
    SAPDB_Char OwnernameBuffer[256];
    SAPDB_Char GroupnameBuffer[256];
    RTE_IniFileResult  ok;
    RTE_IniFileErrtext errtext;

    RTE_GetInstallationConfigString( SAPDB_SAPDBOWNER_KEY, 
                                     OwnernameBuffer, 
                                     (SAPDB_Int4)sizeof(OwnernameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBOWNER_KEY,
                                        errtext
                                      );
        return false;
    }

    RTE_GetInstallationConfigString( SAPDB_SAPDBGROUP_KEY, 
                                     GroupnameBuffer, 
                                     (SAPDB_Int4)sizeof(GroupnameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBGROUP_KEY,
                                        errtext
                                      );
        return false;
    }

    if ( !RTE_GetUserIdFromUsername( OwnernameBuffer,
                                     userId,
                                     errList ) )
    {
        return false;
    }

    if ( !RTE_GetGroupIdFromGroupname( GroupnameBuffer,
                                       groupId,
                                       errList ) )
    {
        return false;
    }

    return true;
}

/*--------------------------*/

SAPDB_Bool
RTE_GetDefaultOwnerAndSupportGroupFromDbroot( SAPDB_Char const *dbroot,
                                              SAPDB_Int4 &userId,
                                              SAPDB_Int4 &groupId,
                                              SAPDBErr_MessageList &errList)
{
    RTE_Path           pathToKernel;

    if ( (strlen(dbroot) + strlen(SUBPATH_TO_KERNEL_EXECUTABLE)) >= sizeof(RTE_Path) )
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_PATH_TOO_LONG,
                                        dbroot
                                      );
        return false;
    }

    strcpy(pathToKernel, dbroot);
    strcat(pathToKernel, SUBPATH_TO_KERNEL_EXECUTABLE);

    return RTE_GetFileOwnerAndGroup(pathToKernel, userId, groupId, errList);
}

/*--------------------------*/
                                
SAPDB_Bool
RTE_GetOwnerAndSupportGroupIdFromDatabaseName( SAPDB_Char const *dbname,
                                               SAPDB_Int4 &userId, 
                                               SAPDB_Int4 &groupId, 
                                               SAPDBErr_MessageList &errList)
{
#if 1
    teo200_EventList oEvent;
    oEvent.eo200_ClearEventList();
    tsp00_Namec szDbname;

    szDbname.rawAssign(dbname);
    teo28_ProfileContainer  oProfile(szDbname, true, &oEvent);

    if (!oEvent) 
    {
        tsp00_Namec szUPCOwner;
        if (!oProfile.eo28_GetOwnerName(szUPCOwner, &oEvent)) 
        {
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_DATABASE_NOT_FOUND,
                                            dbname,
                                            oEvent.eo200_EventMsg()
                                          );
            return false;
        } // end if

        if ( !RTE_GetUserIdFromUsername( szUPCOwner.asCharp(),
                                         userId,
                                         errList ) )
        {
            return false;
        }
        tsp00_Namec szUPCGroup;
        if (!oProfile.eo28_GetGroupName(szUPCGroup, &oEvent)) 
        {
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_DATABASE_NOT_FOUND,
                                            dbname,
                                            oEvent.eo200_EventMsg()
                                          );
            return false;
        } // end if

        if ( !RTE_GetGroupIdFromGroupname( szUPCGroup.asCharp(),
                                           groupId,
                                           errList ) )
        {
            return false;
        }
    } // end if
    else
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_DATABASE_NOT_FOUND,
                                        dbname,
                                        oEvent.eo200_EventMsg()
                                      );
        return false;
    }

    return true;
#else
    RTE_Path           dbRoot;
    RTE_IniFileResult  ok;
    RTE_IniFileErrtext errtext;

    RTE_GetConfigString (SAPDB_DATABASES_INI_FILE, SAPDB_DATABASES_SECTION,
                    	    dbname, dbRoot, sizeof(RTE_Path), errtext, ok);

    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_DATABASE_NOT_FOUND,
                                        dbname,
                                        errtext
                                      );
        return false;
    }

    return RTE_GetDefaultOwnerAndSupportGroupFromDbroot(dbRoot, userId, groupId, errList);
#endif
}

/*---------------------------*/

SAPDB_Bool
RTE_SetFileOwnerAndGroup(SAPDB_Char const *Pathname,
                         SAPDB_Int4 userId,
                         SAPDB_Int4 groupId,
                         SAPDBErr_MessageList &errList)
{
    RTE_SystemRc rc;
    RTESys_ErrorMessage spaceToFill;
    if ( RTE_save_chown(Pathname, userId, groupId) != 0 )
    {
        rc = RTESys_GetLastError();
        if ( RTE_SYSTEMRC_FILE_NOT_FOUND != rc )
        {
            errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                            RTEERR_CHOWN_FAILED,
                                            Pathname,
                                            SAPDB_ToString(userId),
                                            SAPDB_ToString(groupId),
                                            RTESys_StrError(rc, spaceToFill)
                                          );
            return false;
        }
    }

    return true;
}

/*----------------------------------------------*/

SAPDB_Bool
RTE_SetFileOwnerAndGroup(SAPDB_Char const *Pathname,
                         SAPDB_Char const *Username,
                         SAPDB_Char const *Groupname,
                         SAPDBErr_MessageList &errList)
{
    SAPDB_Int4 ownerId;
    SAPDB_Int4 groupId;

    if ( !RTE_GetUserIdFromUsername(Username, ownerId, errList) )
    {
        return false;
    }

    if ( !RTE_GetGroupIdFromGroupname(Groupname, groupId, errList) )
    {
        return false;
    }

    return RTE_SetFileOwnerAndGroup(Pathname, ownerId, groupId, errList);
}

/*----------------------------------------------*/

SAPDB_Bool
RTE_GetFileOwnerAndGroup(SAPDB_Char const *Pathname,
                         SAPDB_Int4 &userId,
                         SAPDB_Int4 &groupId,
                         SAPDBErr_MessageList &errList)
{
    struct stat statBuffer;

    if ( RTE_save_stat(Pathname, &statBuffer) )
    {
        RTE_SystemRc rc = RTESys_GetLastError();
        RTESys_ErrorMessage spaceToFill;
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_STAT_FAILED,
                                       Pathname,
                                       RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    userId = (SAPDB_Int4)statBuffer.st_uid;
    groupId = (SAPDB_Int4)statBuffer.st_gid;

    return true;
}

/*----------------------------------------------*/

SAPDB_Bool
RTE_GetFileOwnerAndGroup(RTE_FileHandle handle,
                         SAPDB_Int4 &userId,
                         SAPDB_Int4 &groupId,
                         SAPDBErr_MessageList &errList)
{
    struct stat statBuffer;

    if ( RTE_save_fstat(handle, &statBuffer) )
    {
        RTE_SystemRc rc = RTESys_GetLastError();
        RTESys_ErrorMessage spaceToFill;
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_FSTAT_FAILED,
                                       SAPDB_ToString(handle),
                                       RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    userId = (SAPDB_Int4)statBuffer.st_uid;
    groupId = (SAPDB_Int4)statBuffer.st_gid;

    return true;
}

/*----------------------------------------------*/

SAPDB_Bool
RTE_GetFileOwnerAndGroup(SAPDB_Char const *Pathname,
                         SAPDB_Char *UsernameBuffer,
                         SAPDB_Int4  UsernameBufferSize,
                         SAPDB_Char *GroupnameBuffer,
                         SAPDB_Int4  GroupnameBufferSize,
                         SAPDBErr_MessageList &errList)
{
    SAPDB_Int4 userId;
    SAPDB_Int4 groupId;

    SAPDBERR_ASSERT_STATE(UsernameBuffer != 0);
    SAPDBERR_ASSERT_STATE(UsernameBufferSize > 0);
    SAPDBERR_ASSERT_STATE(GroupnameBuffer != 0);
    SAPDBERR_ASSERT_STATE(GroupnameBufferSize > 0);

    if ( !RTE_GetFileOwnerAndGroup(Pathname,
                                   userId,
                                   groupId,
                                   errList) )
    {
        return false;
    }

    if ( !RTE_GetUsernameFromUserId( userId,
                                     UsernameBuffer,
                                     UsernameBufferSize,
                                     errList) )
    {
        return false;
    }

    if ( !RTE_GetGroupnameFromGroupId( groupId,
                                       GroupnameBuffer,
                                       GroupnameBufferSize,
                                       errList) )
    {
        return false;
    }

    return true;
}

/*----------------------------------------------*/

SAPDB_Bool
RTE_GetFileOwnerAndGroup(RTE_FileHandle handle,
                         SAPDB_Char *UsernameBuffer,
                         SAPDB_Int4  UsernameBufferSize,
                         SAPDB_Char *GroupnameBuffer,
                         SAPDB_Int4  GroupnameBufferSize,
                         SAPDBErr_MessageList &errList)
{
    SAPDB_Int4 userId;
    SAPDB_Int4 groupId;

    SAPDBERR_ASSERT_STATE(UsernameBuffer != 0);
    SAPDBERR_ASSERT_STATE(UsernameBufferSize > 0);
    SAPDBERR_ASSERT_STATE(GroupnameBuffer != 0);
    SAPDBERR_ASSERT_STATE(GroupnameBufferSize > 0);

    if ( !RTE_GetFileOwnerAndGroup(handle,
                                   userId,
                                   groupId,
                                   errList) )
    {
        return false;
    }

    if ( !RTE_GetUsernameFromUserId( userId,
                                     UsernameBuffer,
                                     UsernameBufferSize,
                                     errList) )
    {
        return false;
    }

    if ( !RTE_GetGroupnameFromGroupId( groupId,
                                       GroupnameBuffer,
                                       GroupnameBufferSize,
                                       errList) )
    {
        return false;
    }

    return true;
}

/*--------------------*/

SAPDB_Bool
RTE_VerifyUserAsSapdbAdministrator(
    SAPDB_Char const *Username,
    SAPDBErr_MessageList &errList)
{
    RTE_IniFileResult  ok;
    RTE_IniFileErrtext errtext;
    SAPDB_Char UsernameBuffer[256];
    SAPDB_Char GroupnameBuffer[256];
    SAPDB_Int4 userId;
    SAPDB_Int4 primaryGroupId;

    SAPDBERR_ASSERT_STATE(Username != 0);

    /* First get user id and primary group id */
    if ( !RTE_GetUserAndPrimaryGroupIdFromUsername( Username,
                                                    userId,
                                                    primaryGroupId,
                                                    errList ) )
    {
        return false;
    }

    /* let superuser be always administrator */
    if ( 0 == userId )
    {
        return true;
    }

    /* now get SdbOwner */
    RTE_GetInstallationConfigString( SAPDB_SAPDBOWNER_KEY, 
                                     UsernameBuffer, 
                                     (SAPDB_Int4)sizeof(UsernameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBOWNER_KEY,
                                        errtext
                                      );
        return false;
    }

    /* Check if SdbOwner matches */
    SAPDB_Int iCheck;
 	for ( iCheck = 0; Username[iCheck] != 0; ++iCheck )
 	{
 		if ( toupper(Username[iCheck]) != toupper(UsernameBuffer[iCheck]) )
 		{
 			break;
 		}
 	}
 	if ( toupper(Username[iCheck]) == toupper(UsernameBuffer[iCheck]) )
    {
 	    return true; /* SdbOwner is always administrator */
    }
 
    /* now get SdbAdmin group */
    RTE_GetInstallationConfigString( SAPDB_SAPDBGROUP_KEY, 
                                     GroupnameBuffer, 
                                     (SAPDB_Int4)sizeof(GroupnameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBOWNER_KEY,
                                        errtext
                                      );
        return false;
    }

    struct group *grEntry;
    {
        RTESync_LockedScope scope(lock);
        grEntry = getgrnam(GroupnameBuffer);
    }
    if ( !grEntry )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_GROUP_UNKNOWN,
                                       GroupnameBuffer);
        return false;
    }

    /* if primary group matches, user is member of database administrator group */
    if ( primaryGroupId == grEntry->gr_gid )
    {
        return true;
    }

    /* otherwise he must be explicitly listed in member list */
    for ( SAPDB_Char **memberList = grEntry->gr_mem; memberList && *memberList; ++memberList )
    {
        for ( iCheck = 0; Username[iCheck] != 0; ++iCheck )
        {
            if ( toupper(Username[iCheck]) != toupper((*memberList)[iCheck]) )
            {
                break;
            }
        }

        if ( toupper(Username[iCheck]) != toupper((*memberList)[iCheck]) )
        {
            continue;
        }

        return true; /* ok we found him */
    }

    errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                   RTEERR_USER_NOT_MEMBER_IN_GROUP,
                                   Username,
                                   GroupnameBuffer);
    return false;
}

/*--------------------*/

SAPDB_Bool
RTE_VerifyUserIdGroupIdCombinationAsSapdbAdministrator(
    SAPDB_Int4 userId,
    SAPDB_Int4 primaryGroupId,
    SAPDBErr_MessageList &errList)
{
    RTE_IniFileResult  ok;
    RTE_IniFileErrtext errtext;
    SAPDB_Char GroupnameBuffer[256];

    /* let superuser be always administrator */
    if ( 0 == userId )
    {
        return true;
    }

    /* now get SdbAdmin group */
    RTE_GetInstallationConfigString( SAPDB_SAPDBGROUP_KEY, 
                                     GroupnameBuffer, 
                                     (SAPDB_Int4)sizeof(GroupnameBuffer),
                                     errtext,
                                     ok );
    if ( SAPDB_INIFILE_RESULT_OK != ok)
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_REGISTRY_KEY_NOT_FOUND,
                                        SAPDB_SAPDBOWNER_KEY,
                                        errtext
                                      );
        return false;
    }

    struct group *grEntry;
    {
        RTESync_LockedScope scope(lock);
        grEntry = getgrnam(GroupnameBuffer);
    }
    if ( !grEntry )
    {
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_GROUP_UNKNOWN,
                                       GroupnameBuffer);
        return false;
    }

    /* if primary group matches, user is member of database administrator group */
    if ( primaryGroupId == grEntry->gr_gid )
    {
        return true;
    }

    gid_t processGroupList[NGROUPS_MAX];
    int nGroups = getgroups(NGROUPS_MAX, processGroupList);
    if ( nGroups < 0 )
    {
        RTE_SystemRc rc = RTESys_GetLastError();
        RTESys_ErrorMessage spaceToFill;
        errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                       RTEERR_CANNOT_GET_PROCESS_GROUP_LIST,
                                       SAPDB_ToString(NGROUPS_MAX),
                                       RTESys_StrError(rc, spaceToFill) );
    }

    /* otherwise he must be explicitly listed in process group list */
    for ( int iGroup = 0; iGroup < nGroups; iGroup++ )
    {
        if ( grEntry->gr_gid == processGroupList[iGroup] )
        {
            return true; /* ok we found him */
        }
    }

    errList = SAPDBErr_MessageList(RTE_CONTEXT,
                                   RTEERR_USER_NOT_MEMBER_IN_GROUP,
                                   SAPDB_ToString(userId),
                                   GroupnameBuffer);
    return false;
}

/*--------------------*/

SAPDB_Bool
RTE_VerifyAsSapdbAdministrator(
    SAPDBErr_MessageList &errList)
{
    return RTE_VerifyUserIdGroupIdCombinationAsSapdbAdministrator(
        (SAPDB_Int4)RTE_save_getuid(),
        (SAPDB_Int4)RTE_save_getgid(),
        errList );
}


/*----------------------*/
#ifndef NO_CRYPT

#define RTE_VERIFY_PASSWORD_CALL "dbmverifypw"

SAPDB_Bool
RTE_VerifyUserPasswordCombination(
    SAPDB_Char const     *username,
    SAPDB_Char const     *passwd,
    SAPDBErr_MessageList &errList)
{
    RTE_SystemRc rc;
    RTESys_ErrorMessage spaceToFill;
    pid_t child;
    int pipeClientInput[2];
    int pipeClientOutput[2];
    char inputPipe[20];
    char outputPipe[20];
    tsp00_Pathc   binPath;
    tsp01_RteError rteError;
    SAPDB_Int4 userId;

    /* First make sure user exists, to prevent really ugly messages... */
    if ( !RTE_GetUserIdFromUsername(username, userId, errList) )
    {
        return false;
    }

    if ( !sqlGetDbrootPgmPath( binPath,
                               TERM_WITH_DELIMITER_EO01,
                               &rteError ) )
    {
        rc = RTESys_GetLastError();
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "Failed to get dependent pgm path",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    if ( (strlen(binPath.asCharp()) + strlen(RTE_VERIFY_PASSWORD_CALL)) > sizeof(tsp00_Path) )
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "Path to verify password call executable too long" );
        return false;
    }

    strcat(binPath.asCharp(), RTE_VERIFY_PASSWORD_CALL);

    if ( RTE_save_access(binPath.asCharp(), X_OK) != 0 )
    {
        rc = RTESys_GetLastError();
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "access to verify command failed",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    if ( 0 != pipe(pipeClientInput) )
    {
        rc = RTESys_GetLastError();
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "input pipe creation for password verification",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    if ( 0 != pipe(pipeClientOutput) )
    {
        rc = RTESys_GetLastError();
        close(pipeClientInput[0]);
        close(pipeClientInput[1]);
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "output pipe creation for password verification",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    SAPDB_sprintf(inputPipe, sizeof(inputPipe), "%d", pipeClientInput[0]);
    SAPDB_sprintf(outputPipe, sizeof(outputPipe), "%d", pipeClientOutput[1]);

    child = fork();
    if ( child == (pid_t)-1 )
    {
        rc = RTESys_GetLastError();
        close(pipeClientInput[0]);
        close(pipeClientInput[1]);
        close(pipeClientOutput[0]);
        close(pipeClientOutput[1]);
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "fork of verification process",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    if ( child == (pid_t)0 )
    {
        char *cArgv[5];
        extern char **environ;

        close(pipeClientInput[1]);
        close(pipeClientOutput[0]);
        cArgv[0] = strdup(binPath.asCharp());
        cArgv[1] = strdup(username);
        cArgv[2] = strdup(inputPipe);
        cArgv[3] = strdup(outputPipe);
        cArgv[4] = 0;
        RTE_save_execve(cArgv[0], cArgv, environ);
        _exit(89);
    }

    close(pipeClientInput[0]);
    close(pipeClientOutput[1]);
    char cryptBuffer[1024];   /* Needed for MD5 and blowfish encrytped passwords */
    memset(cryptBuffer, 0, 1024);
    memset(cryptBuffer, ' ', 15);

    if ( read(pipeClientOutput[0], cryptBuffer, 1024) <= 1 )
    {
        rc = RTESys_GetLastError();
        close(pipeClientInput[1]);
        close(pipeClientOutput[0]);
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "pipe read for password verification",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    char const * GeneratedPassword;
    if ( passwd )
    {
        GeneratedPassword = crypt (passwd, cryptBuffer);
        if ( !GeneratedPassword || !*GeneratedPassword )
        {
            {
                GeneratedPassword = "??";
            }
        }
    }
    else
    {
        /* Empty password is not crypted... */
        GeneratedPassword = "";
    }

    if ( write(pipeClientInput[1], GeneratedPassword, strlen(GeneratedPassword) + 1  ) != (strlen(GeneratedPassword) + 1) )
    {
        rc = RTESys_GetLastError();
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_COMMAND_PIPE_OPEN,
                                        "pipe write for password verification",
                                        RTESys_StrError(rc, spaceToFill) );
        return false;
    }

    close(pipeClientInput[1]);
    close(pipeClientOutput[0]);

    int exitStatus = 0;
    pid_t donePid;

    while ( (donePid = waitpid(child, &exitStatus, 0)) != child )
    {
        if ( donePid == (pid_t)-1
             && errno == EINTR )
        {
           continue;
        }
        else
        {
            exitStatus = -2;
            break;
        }
    }

    if ( exitStatus != 0 )
    {
        errList = SAPDBErr_MessageList( RTE_CONTEXT,
                                        RTEERR_PASSWORD_MISMATCH );
        return false;
    }

    return true;
}

/*--------------------*/

SAPDB_Bool
RTE_VerifyUserAsSapdbAdministrator(
    SAPDB_Char const     *username,
    SAPDB_Char const     *passwd,
    SAPDBErr_MessageList &errList)
{
    if ( passwd )
    {
        if ( !RTE_VerifyUserPasswordCombination(username, passwd, errList) )
        {
            return false;
        }
    }

    return RTE_VerifyUserAsSapdbAdministrator(username, errList);
}

#endif /* NO_CRYPT */
