#!/usr/bin/python3

# Copyright (c) 2010 Peter Palfrader <peter@palfrader.org>

# This script, non-interactively, sets a great many accounts to
# 'retiring', locking their password, removing keys, setting shadow
# information to expired and setting accountstatus appropriatly.


#   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.

from __future__ import print_function

import getpass
import sys
import optparse
import os
import pwd
import time

import ldap

from userdir_ldap.ldap import connectLDAP, BaseDn
from userdir_ldap import UDLdap

dry_run = False


def connect(user):
    lc = connectLDAP()
    binddn = "uid=%s,%s" % (user, BaseDn)
    bindpw = None
    if 'LDAP_PASSWORD' in os.environ:
        bindpw = os.environ['LDAP_PASSWORD']
    else:
        bindpw = getpass.getpass(user + "'s password: ")

    try:
       lc.simple_bind_s(binddn, bindpw)
    except ldap.LDAPError as e:
       sys.stderr.write("LDAP error: %s\n" % e.args[0]['desc'])
       sys.exit(1)
    return lc


def do_one_user(lc, user, ticket, status):
    try:
        u = UDLdap.Account.from_search(lc, BaseDn, user)
    except IndexError as e:
        sys.stderr.write("Cannot instantiate account from LDAP: %s" % str(e))
        return
    if not u['accountStatus'] == 'active':
        sys.stderr.write('%s: Account is not active, skipping.  (details: %s)\n' % (user, u.verbose_status()))
        return

    print('%s: Setting to %s:' % (user, status))
    set = {}
    set['userPassword'] = '{crypt}*LK*'
    set['shadowLastChange'] = str(int(time.time() / 24 / 60 / 60))
    set['shadowExpire'] = '1'
    set['accountStatus'] = '%s %s' % (status, time.strftime('%Y-%m-%d'))
    if ticket is not None:
        set['accountComment'] = "RT#%s" % ticket

    rec = []
    for key in set:
        print('  %s: %s' % (key, set[key]))
        rec.append((ldap.MOD_REPLACE, key, set[key].encode("utf-8")))

    if u.numkeys() > 0:
        print('  %s: deleting keyFingerPrint' % user)
        rec.append((ldap.MOD_DELETE, 'keyFingerPrint', None))

    if dry_run:
        print('(not committing)')
    else:
        lc.modify_s(u.get_dn(), rec)
        print('%s: done.' % user)

    sys.stdout.flush()


parser = optparse.OptionParser()
parser.set_usage("%prog [--admin-user <binduser>] [--no-do] <account> [<account> ...]")
parser.add_option("-a", "--admin-user", dest="admin", metavar="admin",
                  help="User to bind as.",
                  default=pwd.getpwuid(os.getuid()).pw_name)
parser.add_option("-n", "--no-do", action="store_true",
                  help="Do not actually change anything.")
parser.add_option("-r", "--rt-ticket", dest="ticket", metavar="ticket#",
                  help="Ticket number for accountComment.")
parser.add_option("-s", "--status", dest="status", metavar="status",
                  default='retiring',
                  help="Set status to <status> (default: retiring).")

(options, args) = parser.parse_args()

if options.no_do:
    dry_run = True

lc = connect(options.admin)
for user in args:
    do_one_user(lc, user, options.ticket, options.status)


# vim:set et:
# vim:set ts=4:
# vim:set shiftwidth=4:
