CasperSecurity

Current Path : /home/uiet/iRedMail-1.5.0/tools/
Upload File :
Current File : //home/uiet/iRedMail-1.5.0/tools/create_mail_user_OpenLDAP.py

#!/usr/bin/env python3
# encoding: utf-8

# Author: Zhang Huangbin <zhb _at_ iredmail.org>
# Purpose: Add new OpenLDAP user for postfix mail server.
# Project:  iRedMail (http://www.iredmail.org/)

# --------------------------- WARNING ------------------------------
# This script only works under iRedMail >= 0.4.0 due to ldap schema
# changes.
# ------------------------------------------------------------------

# ---------------------------- USAGE -------------------------------
# Put your user list in a csv format file, e.g. users.csv, and then
# import users listed in the file:
#
#   $ python3 create_mail_user_OpenLDAP.py users.csv
#
# ------------------------------------------------------------------

# ------------------------- SETTINGS -------------------------------
# LDAP server address.
LDAP_URI = 'ldap://127.0.0.1:389'

# LDAP base dn.
BASEDN = 'o=domains,dc=example,dc=com'

# Bind dn/password
BINDDN = 'cn=Manager,dc=example,dc=com'
BINDPW = 'password'

# Storage base directory.
STORAGE_BASE_DIRECTORY = '/var/vmail/vmail1'

# Append timestamp in maildir path.
APPEND_TIMESTAMP_IN_MAILDIR = True

# Get base directory and storage node.
std = STORAGE_BASE_DIRECTORY.rstrip('/').split('/')
STORAGE_NODE = std.pop()
STORAGE_BASE = '/'.join(std)

# Hashed maildir: True, False.
# Example:
#   domain: domain.ltd,
#   user:   zhang (zhang@domain.ltd)
#
#       - hashed: d/do/domain.ltd/z/zh/zha/zhang/
#       - normal: domain.ltd/zhang/
HASHED_MAILDIR = True

# Default password schemes.
# Multiple passwords are supported if you separate schemes with '+'.
# For example: 'SSHA+NTLM', 'CRAM-MD5+SSHA', 'CRAM-MD5+SSHA+MD5'.
DEFAULT_PASSWORD_SCHEME = 'SSHA512'

# Do not prefix password scheme name in password hash.
HASHES_WITHOUT_PREFIXED_PASSWORD_SCHEME = ['NTLM']
# ------------------------------------------------------------------

import os
import sys
import time
import datetime
from subprocess import Popen, PIPE
from typing import List, Dict
import re

try:
    import ldif
except ImportError:
    print("""
    Error: You don't have python-ldap installed, Please install it first.

    You can install it like this:

    - On RHEL/CentOS 5.x:

        $ sudo yum install python-ldap

    - On Debian & Ubuntu:

        $ sudo apt install python-ldap
    """)
    sys.exit()


def usage():
    print("""
CSV file format:

    domain name, username, password, [common name], [quota_in_bytes], [groups]

Example #1:
    iredmail.org, zhang, plain_password, Zhang Huangbin, 104857600, group1:group2
Example #2:
    iredmail.org, zhang, plain_password, Zhang Huangbin, ,
Example #3:
    iredmail.org, zhang, plain_password, , 104857600, group1:group2

Note:
    - Domain name, username and password are REQUIRED, others are optional:
        + common name.
            * It will be the same as username if it's empty.
            * Non-ascii character is allowed in this field, they will be
              encoded automaticly. Such as Chinese, Korea, Japanese, etc.
        + quota. It will be 0 (unlimited quota) if it's empty.
        + groups.
            * valid group name (hr@a.cn): hr
            * incorrect group name: hr@a.cn
            * Do *NOT* include domain name in group name, it will be
              appended automaticly.
            * Multiple groups must be seperated by colon.
    - Leading and trailing Space will be ignored.
    """)


def __str2bytes(s) -> bytes:
    """Convert `s` from string to bytes."""
    if isinstance(s, bytes):
        return s
    elif isinstance(s, str):
        return s.encode()
    elif isinstance(s, (int, float)):
        return str(s).encode()
    else:
        return bytes(s)

def __attr_ldif(attr, value, default=None) -> List:
    """Generate a list of LDIF data with given attribute name and value.
    Returns empty list if no valid value.

    Value is properly handled with str/bytes/list/tuple/set types, and
    converted to list of bytes at the end.

    To generate ldif list with ldap modification like `ldap.MOD_REPLACE`,
    please use function `mod_replace()` instead.
    """
    _ldif = []
    v = value or default
    if v:
        if isinstance(value, (list, tuple, set)):
            lst = []
            for i in v:
                # Avoid duplicate element.
                if i in lst:
                    continue

                if isinstance(i, bytes):
                    lst.append(i)
                else:
                    lst.append(__str2bytes(i))

            _ldif = [(attr, lst)]
        else:
            _ldif = [(attr, [__str2bytes(v)])]

    return _ldif


def __attrs_ldif(kvs: Dict) -> List:
    lst = []
    for (k, v) in kvs.items():
        lst += __attr_ldif(k, v)

    return lst


# Return list of modification operation.
def mail_to_user_dn(mail):
    """Convert email address to ldap dn of normail mail user."""
    if mail.count('@') != 1:
        return ''

    user, domain = mail.split('@')

    # User DN format.
    # mail=user@domain.ltd,domainName=domain.ltd,[LDAP_BASEDN]
    dn = 'mail=%s,ou=Users,domainName=%s,%s' % (mail, domain, BASEDN)

    return dn


def generate_password_with_doveadmpw(plain_password, scheme=None):
    """Generate password hash with `doveadm pw` command.
    Return SSHA instead if no 'doveadm' command found or other error raised."""
    if not scheme:
        scheme = DEFAULT_PASSWORD_SCHEME

    scheme = scheme.upper()
    p = str(plain_password).strip()

    pp = Popen(['doveadm', 'pw', '-s', scheme, '-p', p], stdout=PIPE)
    pw = pp.communicate()[0]

    if scheme in HASHES_WITHOUT_PREFIXED_PASSWORD_SCHEME:
        pw.lstrip('{' + scheme + '}')

    # remove '\n'
    pw = pw.strip()

    return pw

def get_days_of_today():
    """Return number of days since 1970-01-01."""
    today = datetime.date.today()

    try:
        return (datetime.date(today.year, today.month, today.day) - datetime.date(1970, 1, 1)).days
    except:
        return 0

def ldif_mailuser(domain, username, passwd, cn, quota, groups=''):
    # Append timestamp in maildir path
    DATE = time.strftime('%Y.%m.%d.%H.%M.%S')
    TIMESTAMP_IN_MAILDIR = ''
    if APPEND_TIMESTAMP_IN_MAILDIR:
        TIMESTAMP_IN_MAILDIR = '-%s' % DATE

    if quota == '':
        quota = '0'

    # Remove SPACE in username.
    username = str(username).lower().strip().replace(' ', '')

    if cn == '':
        cn = username

    mail = username + '@' + domain
    dn = mail_to_user_dn(mail)

    # Get group list.
    if groups.strip() != '':
        groups = groups.strip().split(':')
        for i in range(len(groups)):
            groups[i] = groups[i] + '@' + domain

    maildir_domain = str(domain).lower()
    if HASHED_MAILDIR is True:
        str1 = str2 = str3 = username[0]
        if len(username) >= 3:
            str2 = username[1]
            str3 = username[2]
        elif len(username) == 2:
            str2 = str3 = username[1]

        maildir_user = "%s/%s/%s/%s%s/" % (str1, str2, str3, username, TIMESTAMP_IN_MAILDIR, )
        mailMessageStore = maildir_domain + '/' + maildir_user
    else:
        mailMessageStore = "%s/%s%s/" % (domain, username, TIMESTAMP_IN_MAILDIR)

    homeDirectory = STORAGE_BASE_DIRECTORY + '/' + mailMessageStore
    mailMessageStore = STORAGE_NODE + '/' + mailMessageStore

    _ldif = __attrs_ldif({
        'objectClass': ['inetOrgPerson', 'mailUser', 'shadowAccount', 'amavisAccount'],
        'mail': mail,
        'userPassword': generate_password_with_doveadmpw(passwd),
        'mailQuota': quota,
        'cn': cn,
        'sn': username,
        'uid': username,
        'storageBaseDirectory': STORAGE_BASE,
        'mailMessageStore': mailMessageStore,
        'homeDirectory': homeDirectory,
        'accountStatus': 'active',
        'enabledService': ['internal', 'doveadm', 'lib-storage',
                           'indexer-worker', 'dsync', 'quota-status',
                           'mail',
                           'smtp', 'smtpsecured', 'smtptls',
                           'pop3', 'pop3secured', 'pop3tls',
                           'imap', 'imapsecured', 'imaptls',
                           'managesieve', 'managesievesecured', 'managesievetls',
                           'sieve', 'sievesecured', 'sievetls',
                           'deliver', 'lda', 'lmtp', 'forward',
                           'senderbcc', 'recipientbcc',
                           'sogo', 'sogowebmail', 'sogocalendar', 'sogoactivesync',
                           'shadowaddress',
                           'displayedInGlobalAddressBook'],
        'memberOfGroup': groups,
        # shadowAccount integration.
        'shadowLastChange': get_days_of_today(),
        # Amavisd integration.
        'amavisLocal': 'TRUE',
    })

    return dn, _ldif


if len(sys.argv) != 2 or len(sys.argv) > 2:
    print("""Usage: $ python3 %s users.csv""" % sys.argv[0])
    usage()
    sys.exit()
else:
    CSV = sys.argv[1]
    if not os.path.exists(CSV):
        print("Error: file not exist:", CSV)
        sys.exit()

ldif_file = CSV + '.ldif'

# Remove exist LDIF file.
if os.path.exists(ldif_file):
    print("< INFO > Remove exist file:", ldif_file)
    os.remove(ldif_file)

# Read user list.
userList = open(CSV, 'rb')

# Convert to LDIF format.
for entry in userList.readlines():
    entry = entry.decode().rstrip()
    domain, username, passwd, cn, quota, groups = re.split(r'\s?,\s?', entry)
    dn, data = ldif_mailuser(domain, username, passwd, cn, quota, groups)

    # Write LDIF data.
    result = open(ldif_file, 'a')
    ldif_writer = ldif.LDIFWriter(result)
    ldif_writer.unparse(dn, data)


ldif_file_path = os.path.abspath(ldif_file)
print("< INFO > User data are stored in %s, you can verify it before importing it." % ldif_file_path)
print("< INFO > You can import it with below command:")
print("ldapadd -x -D %s -W -f %s" % (BINDDN, ldif_file_path))

# Prompt to import user data.
"""
answer = raw_input("Would you like to import them now? [y|N]").lower().strip()

if answer == 'y':
    # Import data.
    conn = ldap.initialize(LDAP_URI)
    conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)   # Use LDAP v3
    conn.bind_s(BINDDN, BINDPW)
    conn.unbind()
else:
    pass
"""
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY