This file is indexed.

/usr/share/pyshared/passlib/handlers/django.py is in python-passlib 1.5.3-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"""passlib.handlers.django- Django password hash support"""
#=========================================================
#imports
#=========================================================
#core
from hashlib import md5, sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
from passlib.utils import h64, handlers as uh, b, bytes, to_unicode, to_hash_str
#pkg
#local
__all__ = [
    "django_salted_sha1",
    "django_salted_md5",
    "django_des_crypt",
    "django_disabled",
]

#=========================================================
# lazy imports
#=========================================================
des_crypt = None

def _import_des_crypt():
    global des_crypt
    if des_crypt is None:
        from passlib.hash import des_crypt
    return des_crypt

#=========================================================
#salted hashes
#=========================================================
class DjangoSaltedHash(uh.HasSalt, uh.GenericHandler):
    """base class providing common code for django hashes"""
    #must be specified by subclass - along w/ calc_checksum
    setting_kwds = ("salt", "salt_size")
    ident = None #must have "$" suffix
    _stub_checksum = None

    #common to most subclasses
    min_salt_size = 0
    default_salt_size = 5
    max_salt_size = None
    salt_chars = checksum_chars = uh.LC_HEX_CHARS

    @classmethod
    def identify(cls, hash):
        return uh.identify_prefix(hash, cls.ident)

    @classmethod
    def from_string(cls, hash):
        if not hash:
            raise ValueError("no hash specified")
        if isinstance(hash, bytes):
            hash = hash.decode("ascii")
        ident = cls.ident
        assert ident.endswith(u"$")
        if not hash.startswith(ident):
            raise ValueError("invalid %s hash" % (cls.name,))
        _, salt, chk = hash.split(u"$")
        return cls(salt=salt, checksum=chk, strict=True)

    def to_string(self):
        chk = self.checksum or self._stub_checksum
        out = u"%s%s$%s" % (self.ident, self.salt, chk)
        return to_hash_str(out)

class django_salted_sha1(DjangoSaltedHash):
    """This class implements Django's Salted SHA1 hash, and follows the :ref:`password-hash-api`.

    It supports a variable-length salt, and uses a single round of SHA1.

    The :meth:`encrypt()` and :meth:`genconfig` methods accept the following optional keywords:

    :param salt:
        Optional salt string.
        If not specified, a 5 character one will be autogenerated (this is recommended).
        If specified, may be any series of characters drawn from the regexp range ``[0-9a-f]``.

    :param salt_size:
        Optional number of characters to use when autogenerating new salts.
        Defaults to 5, but can be any non-negative value.
    """
    name = "django_salted_sha1"
    ident = u"sha1$"
    checksum_size = 40
    _stub_checksum = u'0' * 40

    def calc_checksum(self, secret):
        if isinstance(secret, unicode):
            secret = secret.encode("utf-8")
        return to_unicode(sha1(self.salt.encode("ascii") + secret).hexdigest(), "ascii")

class django_salted_md5(DjangoSaltedHash):
    """This class implements Django's Salted MD5 hash, and follows the :ref:`password-hash-api`.

    It supports a variable-length salt, and uses a single round of MD5.

    The :meth:`encrypt()` and :meth:`genconfig` methods accept the following optional keywords:

    :param salt:
        Optional salt string.
        If not specified, a 5 character one will be autogenerated (this is recommended).
        If specified, may be any series of characters drawn from the regexp range ``[0-9a-f]``.

    :param salt_size:
        Optional number of characters to use when autogenerating new salts.
        Defaults to 5, but can be any non-negative value.
    """
    name = "django_salted_md5"
    ident = u"md5$"
    checksum_size = 32
    _stub_checksum = u'0' * 32

    def calc_checksum(self, secret):
        if isinstance(secret, unicode):
            secret = secret.encode("utf-8")
        return to_unicode(md5(self.salt.encode("ascii") + secret).hexdigest(), "ascii")

#=========================================================
#other
#=========================================================

class django_des_crypt(DjangoSaltedHash):
    """This class implements Django's :class:`des_crypt` wrapper, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

    The :meth:`encrypt()` and :meth:`genconfig` methods accept the following optional keywords:

    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    .. note::

        Django only supports this on Unix systems,
        but it is available cross-platform under Passlib.
    """

    name = "django_des_crypt"
    ident = "crypt$"
    checksum_chars = salt_chars = uh.H64_CHARS
    checksum_size = 13
    min_salt_size = 2

    # NOTE: checksum is full des_crypt hash,
    #       including salt as first two digits.
    #       these should always match first two digits
    #       of django_des_crypt's salt...
    #       and all remaining chars of salt are ignored.

    def __init__(self, **kwds):
        super(django_des_crypt, self).__init__(**kwds)

        # make sure salt embedded in checksum is a match,
        # else hash can *never* validate
        salt = self.salt
        chk = self.checksum
        if salt and chk and salt[:2] != chk[:2]:
            raise ValueError("invalid django_des_crypt hash: "
                "first two digits of salt and checksum must match")

    _base_stub_checksum = u'.' * 13

    @property
    def _stub_checksum(self):
        "generate stub checksum dynamically, so it matches always matches salt"
        stub = self._base_stub_checksum
        if self.salt:
            return self.salt[:2] + stub[2:]
        else:
            return stub

    def calc_checksum(self, secret):
        # NOTE: we lazily import des_crypt,
        #       since most django deploys won't use django_des_crypt
        global des_crypt
        if des_crypt is None:
            _import_des_crypt()
        salt = self.salt[:2]
        return salt + des_crypt(salt=salt).calc_checksum(secret)

class django_disabled(uh.StaticHandler):
    """This class provides disabled password behavior for Django, and follows the :ref:`password-hash-api`.

    This class does not implement a hash, but instead
    claims the special hash string ``"!"`` which Django uses
    to indicate an account's password has been disabled.

    * newly encrypted passwords will hash to ``!``.
    * it rejects all passwords.
    """
    name = "django_disabled"

    @classmethod
    def identify(cls, hash):
        if not hash:
            return False
        if isinstance(hash, bytes):
            return hash == b("!")
        else:
            return hash == u"!"

    @classmethod
    def genhash(cls, secret, config):
        if secret is None:
            raise TypeError("no secret provided")
        return to_hash_str(u"!")

    @classmethod
    def verify(cls, secret, hash):
        if not cls.identify(hash):
            raise ValueError("invalid django-disabled hash")
        return False

#=========================================================
#eof
#=========================================================