Permalink
Browse files

Add pwnlib.config module and documentation (#893)

This adds functionality for user configuration files at ~/.pwn.conf
and /etc/pwn.conf.  Previously this was only used by the pwnlib.log
module, and was entirely undocumented.

This is now documented, and offers an easy mechanism for other parts
of the code to have extension points.
  • Loading branch information...
zachriggle committed Feb 13, 2017
1 parent 71855eb commit 658589704af6bb018d3ef5f8108f31aff6daa7ea
Showing with 102 additions and 16 deletions.
  1. +4 −0 docs/source/config.rst
  2. +1 −0 docs/source/index.rst
  3. +1 −0 pwn/__init__.py
  4. +60 −0 pwnlib/config.py
  5. +19 −0 pwnlib/context/__init__.py
  6. +17 −16 pwnlib/log.py
View
@@ -0,0 +1,4 @@
:mod:`pwnlib.config` --- Pwntools Configuration File
====================================================
.. automodule:: pwnlib.config
View
@@ -48,6 +48,7 @@ Each of the ``pwntools`` modules is documented here.
atexception
atexit
constants
config
context
dynelf
encoders
View
@@ -5,6 +5,7 @@
pwnlib.args.initialize()
pwnlib.log.install_default_handler()
pwnlib.config.initialize()
log = pwnlib.log.getLogger('pwnlib.exploit')
args = pwnlib.args.args
View
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
"""Allows per-user and per-host configuration of Pwntools settings.
The list of configurable options includes all of the logging symbols
and colors, as well as all of the default values on the global context
object.
The configuration file is read from ``~/.pwn.conf`` and ``/etc/pwn.conf``.
The configuration file is only read in ``from pwn import *`` mode, and not
when used in library mode (``import pwnlib``). To read the configuration
file in library mode, invoke :func:`.config.initialize`.
The ``context`` section supports complex types, at least as far as is
supported by ``pwnlib.util.safeeval.expr``.
::
[log]
success.symbol=😎
error.symbol=☠
info.color=blue
[context]
adb_port=4141
randomize=1
timeout=60
terminal=['x-terminal-emulator', '-e']
"""
from __future__ import absolute_import
import ConfigParser
import os
registered_configs = {}
def register_config(section, function):
"""Registers a configuration section.
Arguments:
section(str): Named configuration section
function(callable): Function invoked with a dictionary of
``{option: value}`` for the entries in the section.
"""
registered_configs[section] = function
def initialize():
"""Read the configuration files."""
from pwnlib.log import getLogger
log = getLogger(__name__)
c = ConfigParser.ConfigParser()
c.read(['/etc/pwn.conf', os.path.expanduser('~/.pwn.conf')])
for section in c.sections():
if section not in registered_configs:
log.warn("Unknown configuration section %r" % section)
continue
settings = dict(c.items(section))
registered_configs[section](settings)
View
@@ -21,9 +21,11 @@
import socks
from pwnlib.config import register_config
from pwnlib.device import Device
from pwnlib.timeout import Timeout
_original_socket = socket.socket
class _devnull(object):
@@ -1343,3 +1345,20 @@ def setter(*a, **kw):
with context.local(**{k:kw.pop(k) for k,v in kw.items() if isinstance(getattr(ContextType, k, None), property)}):
return function(*a, **kw)
return setter
# Read configuration options from the context section
def update_context_defaults(section):
# Circular imports FTW!
from pwnlib.util import safeeval
from pwnlib.log import getLogger
log = getLogger(__name__)
for key, value in section.items():
if key not in ContextType.defaults:
log.warn("Unknown configuration option %r in section %r" % (key, 'context'))
continue
if isinstance(ContextType.defaults[key], (str, unicode)):
value = safeeval.expr(value)
ContextType.defaults[key] = value
register_config('context', update_context_defaults)
View
@@ -103,6 +103,7 @@
import time
from pwnlib import term
from pwnlib.config import register_config
from pwnlib.context import Thread
from pwnlib.context import context
from pwnlib.exception import PwnlibException
@@ -132,26 +133,26 @@
}
# permit setting logging colors from a configuration file
config = os.path.expanduser('~/.pwn.conf')
if os.path.exists(config):
c = ConfigParser.ConfigParser()
c.read([config])
for section in c.sections():
if section not in _msgtype_prefixes:
def read_log_config(settings):
log = getLogger(__name__)
for key, value in settings.items():
if '.' not in key:
log.warn("Invalid configuration option %r in section %r" % (key, 'log'))
continue
for key, value in c.items(section):
if key == 'color':
try:
_msgtype_prefixes[section][0] = getattr(text, value)
except AttributeError:
pass
msgtype, key = key.split('.', 1)
if key == 'color':
current = _msgtype_prefixes[msgtype][0]
_msgtype_prefixes[msgtype][0] = getattr(text, value, current)
elif key == 'symbol':
_msgtype_prefixes[section][1] = value
elif key == 'symbol':
_msgtype_prefixes[msgtype][1] = value
else:
log.warn("Unknown configuration option %r in section %r" % (key, 'log'))
register_config('log', read_log_config)
# the text decoration to use for spinners. the spinners themselves can be found
# in the `pwnlib.term.spinners` module

0 comments on commit 6585897

Please sign in to comment.