#!/usr/bin/env python

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

# ... 导入相关模块 ...

class MSSQLBannerHandler(ContentHandler):
    """
    该类用于解析和提取Microsoft SQL Server banner信息
    基于XML文件中的数据进行匹配和处理
    """

    def __init__(self, banner, info):
        ContentHandler.__init__(self)

        # 初始化banner信息和状态标志
        self._banner = sanitizeStr(banner or "")  # 清理并存储banner字符串
        self._inVersion = False                   # 是否正在处理版本信息的标志
        self._inServicePack = False               # 是否正在处理ServicePack信息的标志
        self._release = None                      # 发布版本信息
        self._version = ""                        # 版本号
        self._versionAlt = None                   # 替代版本号格式
        self._servicePack = ""                    # ServicePack版本
        self._info = info                         # 存储解析结果的字典

    def _feedInfo(self, key, value):
        """
        将解析到的信息存入结果字典
        """
        value = sanitizeStr(value)

        if value in (None, "None"):
            return

        self._info[key] = value

    def startElement(self, name, attrs):
        """
        处理XML元素开始标签
        """
        if name == "signatures":
            self._release = sanitizeStr(attrs.get("release"))
        elif name == "version":
            self._inVersion = True
        elif name == "servicepack":
            self._inServicePack = True

    def characters(self, content):
        """
        处理XML元素的文本内容
        """
        if self._inVersion:
            self._version += sanitizeStr(content)
        elif self._inServicePack:
            self._servicePack += sanitizeStr(content)

    def endElement(self, name):
        """
        处理XML元素结束标签
        """
        if name == "signature":
            # 检查banner中是否包含匹配的版本信息
            for version in (self._version, self._versionAlt):
                if version and self._banner and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner):
                    # 找到匹配后，保存相关信息
                    self._feedInfo("dbmsRelease", self._release)
                    self._feedInfo("dbmsVersion", self._version)
                    self._feedInfo("dbmsServicePack", self._servicePack)
                    break

            # 重置临时变量
            self._version = ""
            self._versionAlt = None
            self._servicePack = ""

        elif name == "version":
            self._inVersion = False
            self._version = self._version.replace(" ", "")

            # 处理特殊的版本号格式
            match = re.search(r"\A(?P<major>\d+)\.00\.(?P<build>\d+)\Z", self._version)
            self._versionAlt = "%s.0.%s.0" % (match.group('major'), match.group('build')) if match else None

        elif name == "servicepack":
            self._inServicePack = False
            self._servicePack = self._servicePack.replace(" ", "")

def bannerParser(banner):
    """
    根据不同的数据库类型调用相应的处理器来解析banner信息
    """
    xmlfile = None

    # 根据数据库类型选择对应的XML配置文件
    if Backend.isDbms(DBMS.MSSQL):
        xmlfile = paths.MSSQL_XML
    elif Backend.isDbms(DBMS.MYSQL):
        xmlfile = paths.MYSQL_XML
    elif Backend.isDbms(DBMS.ORACLE):
        xmlfile = paths.ORACLE_XML
    elif Backend.isDbms(DBMS.PGSQL):
        xmlfile = paths.PGSQL_XML

    if not xmlfile:
        return

    # 针对MSSQL使用专门的处理器，其他数据库使用通用处理器
    if Backend.isDbms(DBMS.MSSQL):
        handler = MSSQLBannerHandler(banner, kb.bannerFp)
        parseXmlFile(xmlfile, handler)

        handler = FingerprintHandler(banner, kb.bannerFp)
        parseXmlFile(paths.GENERIC_XML, handler)
    else:
        handler = FingerprintHandler(banner, kb.bannerFp)
        parseXmlFile(xmlfile, handler)
        parseXmlFile(paths.GENERIC_XML, handler)