#!/usr/bin/env python

"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.agent import agent
from lib.core.common import Backend
from lib.core.common import Format
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import DBMS
from lib.core.session import setDbms
from lib.core.settings import MAXDB_ALIASES
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint

class Fingerprint(GenericFingerprint):
    def __init__(self):
        """
        初始化Fingerprint类，指定为SAP MaxDB。
        """
        GenericFingerprint.__init__(self, DBMS.MAXDB)

    def _versionCheck(self):
        """
        执行SAP MaxDB的SYSINFO版本检查。
        """
        infoMsg = "executing %s SYSINFO version check" % DBMS.MAXDB
        logger.info(infoMsg)

        # 构建查询语句
        query = agent.prefixQuery("/* NoValue */")
        query = agent.suffixQuery(query)
        payload = agent.payload(newValue=query)
        result = Request.queryPage(payload)

        if not result:
            warnMsg = "unable to perform %s version check" % DBMS.MAXDB
            logger.warning(warnMsg)

            return None

        minor, major = None, None

        # 检查主要版本号
        for version in (6, 7):
            result = inject.checkBooleanExpression("%d=(SELECT MAJORVERSION FROM SYSINFO.VERSION)" % version)

            if result:
                major = version

        # 检查次要版本号
        for version in xrange(0, 10):
            result = inject.checkBooleanExpression("%d=(SELECT MINORVERSION FROM SYSINFO.VERSION)" % version)

            if result:
                minor = version

        if major and minor:
            return "%s.%s" % (major, minor)
        else:
            return None

    def getFingerprint(self):
        """
        获取指纹信息。
        """
        value = ""
        # 获取Web服务器的操作系统指纹
        wsOsFp = Format.getOs("web server", kb.headersFp)

        if wsOsFp:
            value += "%s\n" % wsOsFp

        # 获取后端数据库的操作系统指纹
        if kb.data.banner:
            dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp)

            if dbmsOsFp:
                value += "%s\n" % dbmsOsFp

        blank = " " * 15
        value += "back-end DBMS: "

        if not conf.extensiveFp:
            value += DBMS.MAXDB
            return value

        # 获取活性指纹
        actVer = Format.getDbms() + " (%s)" % self._versionCheck()
        blank = " " * 15
        value += "active fingerprint: %s" % actVer

        if kb.bannerFp:
            value += "\n%sbanner parsing fingerprint: -" % blank

        # 获取HTML错误消息指纹
        htmlErrorFp = Format.getErrorParsedDBMSes()

        if htmlErrorFp:
            value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)

        return value

    def checkDbms(self):
        """
        检测后端数据库是否为SAP MaxDB。
        """
        if not conf.extensiveFp and Backend.isDbmsWithin(MAXDB_ALIASES):
            setDbms(DBMS.MAXDB)

            # 获取Banner信息
            self.getBanner()

            return True

        infoMsg = "testing %s" % DBMS.MAXDB
        logger.info(infoMsg)

        # 检查ALPHA(NULL)是否为NULL
        result = inject.checkBooleanExpression("ALPHA(NULL) IS NULL")

        if result:
            infoMsg = "confirming %s" % DBMS.MAXDB
            logger.info(infoMsg)

            # 检查MAPCHAR(NULL,1,DEFAULTMAP)是否为NULL
            result = inject.checkBooleanExpression("MAPCHAR(NULL,1,DEFAULTMAP) IS NULL")

            if not result:
                warnMsg = "the back-end DBMS is not %s" % DBMS.MAXDB
                logger.warning(warnMsg)

                return False

            setDbms(DBMS.MAXDB)

            self.getBanner()

            return True
        else:
            warnMsg = "the back-end DBMS is not %s" % DBMS.MAXDB
            logger.warning(warnMsg)

            return False

    def forceDbmsEnum(self):
        """
        强制进行数据库枚举。
        """
        if conf.db:
            conf.db = conf.db.upper()
        else:
            conf.db = "USER"

        if conf.tbl:
            conf.tbl = conf.tbl.upper()