aboutsummaryrefslogtreecommitdiffstats
path: root/private/dovecot/hash-passdb.py
blob: abb05a9e4ea2343f18b5bf49d834fde57289933d (plain)
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
#!/usr/bin/env python3
#
# Copyright (c) 2018 Aaron LI
# MIT License
#

"""
Find and hash the plain passwords in "passdb.yml" used to generate
the "passwd" auth database for Dovecot.

The given infile will be updated in place, and the already hashed
passwords are also kept.

NOTE: The "SHA512-CRYPT" scheme is used.
"""

import argparse
import crypt

from ruamel.yaml import YAML

SCHEME = "SHA512-CRYPT"
METHOD = crypt.METHOD_SHA512
yaml = YAML()


def hashpass(word):
    """
    Check the given word, and hash it if it's not hashed.
    """
    if word.startswith("{%s}" % SCHEME):
        # Already hashed
        return word

    salt = crypt.mksalt(METHOD)
    return "{%s}%s" % (SCHEME, crypt.crypt(word, salt))


def main():
    parser = argparse.ArgumentParser(
        description="Find and hash the plain passwords in a YAML file"
    )
    parser.add_argument("infile", help="input passdb.yml")
    args = parser.parse_args()

    data = yaml.load(open(args.infile))
    print("Loaded passdb from file: %s" % args.infile)

    for name, user in data["passdb"].items():
        if "pass" in user:
            oldword = user["pass"]
            user["pass"] = hashpass(oldword)
            if user["pass"] == oldword:
                status = "ok"
            else:
                status = "hashed"
            print("* %s ... [%s]" % (name, status))
        if "devices" in user:
            devices = user["devices"]
            for dev, oldword in devices.items():
                devices[dev] = hashpass(oldword)
                if devices[dev] == oldword:
                    status = "ok"
                else:
                    status = "hashed"
                print("* %s @ %s ... [%s]" % (name, dev, status))

    yaml.dump(data, open(args.infile, "w"))
    print("Dumped hashed passdb to file: %s" % args.infile)


if __name__ == "__main__":
    main()