#! /usr/bin/env python3 
#
# Semplice script per modificare su LDAP i dati di
# scadenza delle password
#
# Copyright (C) 2005-2023 FUSS Project <info@fuss.bz.it>
# Authors: Simone Piccardi <piccardi@truelite.it>
# Claudio Cavalli <ccavalli@fuss.bz.it>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import ldap
from os import *
import re
import getopt, sys
from pathlib import Path

# Attributes/Options correspondance definitions
attributes = { '-m': 'shadowMin',
               '-M': 'shadowMax',
               '-d': 'shadowLastChange',
               '-E': 'shadowExpire',
               '-I': 'shadowInactive',
               '-W': 'shadowWarning' }

# help on line
def usage():
    print("Usage: chage.py [OPTION] user [user]...")
    print("  -h        print this help")
    print("  -D        debug run, just print commands and values")
    print("  -l        just list values")
    print("  -m min_days    number of days for which a password cannot be changed")
    print("  -M max_days    number of days for which a password is valid")
    print("  -W warn        number of days before password expiring warning")
    print("  -I inactive    number of days after password expired disactivation")
    print("  -d  last_day   set last password change day")
    print("  -E  last_day   sed account expiration day")
    print("  -u usr    use ou=usr as base search for user (instead of Users)")
    print("  -p pwd    LDAP access pass (instead of trying read ldap.secret)")
    print()
    print("ARGUMENTS:")
    print("  at least an username")
    print(" ")

# Command line argument processing
try:
    opts, args = getopt.getopt(sys.argv[1:], 'm:M:d:E:I:W:lhDp:u:') 
    optval = {}
    modif = []
    for opt, val in opts:
        if opt in list(attributes.keys()):
            #print opt, attributes[opt]
            if val:
                modif.append( (ldap.MOD_REPLACE, attributes[opt], val.encode('utf-8')) )
            else:
                modif.append( (ldap.MOD_DELETE, attributes[opt], None) )
        else:
            optval[opt]=val

except getopt.GetoptError:
    usage()
    sys.exit(2)


# Get LDAP parameters from standard files
flags  = re.IGNORECASE|re.MULTILINE
try:
    regexp = r'^\s*base\s*(.*)'
    regx   = re.compile(regexp, flags)
    path   = '/etc/ldap/ldap.conf' 
    conf   = Path(path).read_text()
    base   = regx.findall(conf)[0]
    regexp = r'^\s*uri\s*(.*)'
    regx   = re.compile(regexp, flags)
    uri    = regx.findall(conf)[0]
    if '-D' in optval:
        print(base)
        print(uri)
except Exception as e:
    print("cannot read configuration from /etc/ldap/ldap.conf")
    print(e)

# get LDAP password
if  '-p' in optval:
    password = optval['-p']
else:
    try:
        regexp = r'masterPw="(.*)"'
        path   = '/etc/smbldap-tools/smbldap_bind.conf'
        conf   = Path(path).read_text()
        regx   = re.compile(regexp, flags)
        password = regx.findall(conf)[0]
    except Exception as e:
        print("cannot read password from /etc/smbldap-tools/smbldap_bind.conf")
        print(e)
        sys.exit(1)

# LDAP search parameters
if '-u' in optval:
    baseDN = "ou="+optval['-u']+","+base
else:
    baseDN = "ou=Users,"+base

if '-D' in optval:
    print(baseDN)

# LDAP connection
try: 
    l = ldap.initialize(uri)
    l.protocol_version = ldap.VERSION3
    username = "cn=admin,"+base
    l.simple_bind(username, password)
except ldap.LDAPError as e:
    print("Connection error", e)

if '-D' in optval:
    print(username, "/", password)



searchScope = ldap.SCOPE_SUBTREE
retrieveAttributes = list(attributes.values())

# loop over the users in args
for user in args:
    searchFilter = "uid="+user
    try:
        ldap_result_id = l.search(baseDN, searchScope, searchFilter,
                                  retrieveAttributes)
        result_set = []
        count = 0
        while 1:
            result_type, result_data = l.result(ldap_result_id, 0)
            if (result_data == []):
                break
            else:
                if result_type == ldap.RES_SEARCH_ENTRY:
                    result_set.append(result_data)

    except ldap.LDAPError as e:
        print("Search error", e)
    
    if len(result_set) == 0:
        print("User", user, "unknown")
        continue

    if '-l' in optval:
        for i in range(len(result_set)):
            for voce in result_set[i]:
                print(user, voce[0])
                print("\t ->", voce[1])

    if modif:
        for i in range(len(result_set)):
            for voce in result_set[i]:
                dn = voce[0]
                print(user,',', dn)
                print("\t ->", modif)
                if '-D' not in optval:
                    l.modify_s(dn, modif)
