#!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission Option setup / normalization helpers in lib/core/option.py. These exercise the (mostly) pure config-massaging functions that parse, validate and normalize user-supplied option values into the canonical conf.*/kb.* shapes that the rest of sqlmap relies on - WITHOUT touching the network, the DBMS, the filesystem (beyond what bootstrap already set up) or any interactive prompt. option.py mutates the global conf/kb singletons aggressively, so every test that writes a conf/kb field saves and restores it via the _preserve() helper so the shared state stays pristine for the other test files in the suite. """ import contextlib import logging import os import socket import sys import tempfile import unittest sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from _testutils import bootstrap bootstrap() from lib.core.data import conf, kb, logger from lib.core.common import Backend from lib.core.enums import AUTH_TYPE from lib.core.enums import HTTP_HEADER from lib.core.settings import DEFAULT_USER_AGENT from lib.core.settings import IGNORE_CODE_WILDCARD from lib.core.settings import MAX_CONNECT_RETRIES from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUnsupportedDBMSException from lib.core.exception import SqlmapValueException from thirdparty.six.moves import urllib as _urllib import lib.core.option as option _SENTINEL = object() # scratchpad for the preprocess/postprocess/safe-req fixture files _SCRATCH = os.environ.get("CLAUDE_SCRATCH") or os.path.join(os.path.dirname(os.path.abspath(__file__)), "_option_more_tmp") # conf/kb fields that Backend.getIdentifiedDbms()/getOs() consult; any test that # might touch DBMS/OS forcing snapshots ALL of them so no fingerprint state leaks # into sibling test files (e.g. test_target_parsing's resume tests). _BACKEND_CONF_KEYS = ("dbms", "forceDbms", "os") _BACKEND_KB_KEYS = ("dbms", "dbmsVersion", "forcedDbms", "dbmsFilter", "os", "osVersion", "osSP") def tearDownModule(): """Remove the scratch fixture directory so it never lingers on disk (and so a stray __init__.py there can't shadow imports in a subsequent run).""" import shutil if os.path.isdir(_SCRATCH): shutil.rmtree(_SCRATCH, ignore_errors=True) class _BackendGuard(unittest.TestCase): """Mixin: fully snapshot & restore Backend-relevant conf/kb state per test.""" def setUp(self): super(_BackendGuard, self).setUp() self._snap_conf = {k: (conf[k] if k in conf else _SENTINEL) for k in _BACKEND_CONF_KEYS} self._snap_kb = {k: (kb[k] if k in kb else _SENTINEL) for k in _BACKEND_KB_KEYS} def tearDown(self): for store, snap, keys in ((conf, self._snap_conf, _BACKEND_CONF_KEYS), (kb, self._snap_kb, _BACKEND_KB_KEYS)): for k in keys: if snap[k] is _SENTINEL: try: del store[k] except KeyError: pass else: store[k] = snap[k] super(_BackendGuard, self).tearDown() @contextlib.contextmanager def _preserve(target, *keys): """Save the given keys of an AttribDict (conf/kb), then restore on exit. Missing keys are restored to absent so a test can't leak a brand-new field. """ saved = {} for key in keys: saved[key] = target[key] if key in target else _SENTINEL try: yield finally: for key in keys: if saved[key] is _SENTINEL: try: del target[key] except KeyError: pass else: target[key] = saved[key] class _ImportSandboxMixin(object): """Loaders in option.py (tamper/preprocess/postprocess) permanently `sys.path.insert(0,