#!/usr/bin/python
# -*- coding: utf-8 -*-
#  privacyIDEA is a fork of LinOTP
#  May 08, 2014 Cornelius Kölbel
#  Jul 16, 2014 Cornelius Kölbel: add machine functions
#  License:  AGPLv3
#  contact:  http://www.privacyidea.org
#
#  Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH
#  License:  AGPLv3
#  contact:  http://www.linotp.org
#            http://www.lsexperts.de
#            linotp@lsexperts.de
'''
  Description:  This is the admin client to manage the tokens
                on the privacyIDEA server

  Dependencies: clientutils

'''

VERSION = '1.3'

import subprocess
import datetime
from getopt import getopt, GetoptError
import getpass
from privacyideautils.clientutils import showresult
from privacyideautils.clientutils import dumpresult
from privacyideautils.clientutils import privacyideaclient
from privacyideautils.clientutils import ldap_opts
from privacyideautils.clientutils import file_opts
from privacyideautils.clientutils import initetng
from privacyideautils.clientutils import etng
from privacyideautils.clientutils import pyToken
from privacyideautils.yubikey import enrollYubikey
from privacyideautils.yubikey import YubikeyPlug
from privacyideautils.yubikey import create_static_password
import ConfigParser
import smtplib
import binascii
from email.mime.text import MIMEText
import sys
import os


YUBI_STATIC_MODE = 3
YUBI_OATH_MODE = 2
YUBI_AES_MODE = 1

EDITION = "CE"

REALM = "privacyIDEA admin area (admin/admin)"
COMMANDS = ['listtoken', 'inittoken', 'assigntoken',
            'importtoken', 'disabletoken', 'enabletoken',
            'resynctoken', 'removetoken', 'set',
            'unassigntoken', 'listuser', 'getconfig', 'setconfig',
            'getrealms', 'setrealm', 'deleterealm', 'setdefaultrealm',
            'getresolvers', 'deleteresolver', 'setresolver', 'loadtokens',
            'yubikey_mass_enroll', 'etokenng_mass_enroll',
            'securitymodule',
            'createmachine', 'showmachine', 'deletemachine',
            'machine_addtoken', 'machine_showtoken', 'machine_deltoken',
            'machine_addoption', 'machine_deloption',
            'gettokenapps'
            ]


def usage():
    print("usage: %s --url=<url> --admin=<adminusername> --cert=<cert> "
          "--key=<rsakey> --command=<command> --version" % sys.argv[0])
    print """"  --url/-U     : The base url of the privacyIDEA server. Something like
                 http://localhost:5000 or https://privacyidea:443
  --admin/-a   : If the admin interface of the privacyIDEA service requires authentication
                 you need to pass the username and will be asked for the password.
  --password   : The password of the admin. You should not use this option, since the password would
    print "                 visible in the process list and history.
  --authtype   : The default authtype is 'Digest'. You may change this to 'Basic'
  --cert/-c    : If the admin interface of the privacyIDEA service requires authentication via client certificate
                 you may pass a P12 file here.
  --key/-k     : The private key for authenticating
  --admin/-a   : The name of the administrative account, when authenticating with username/password
  --version/-v : Print version
  --help/-h    : Print this help screen
  --automate   : read parameters from a config file to be used for automation

  --command/-C :
    listtoken:    [--user | --serial ] [--csv]
    listuser:
    inittoken:    --user= --serial= --description= --pin= --otpkey=
                          --etng --pytoken --type=<type>
    inittoken:    --user= --serial= --description= --pin= --otpkeyc=
    yubikey_mass_enroll
        --yubiprefix=<string>
        --yubiprefixrandom=<length>
        --yubiprefixserial          : use the serial of the yubikey as prefix
        --yubimode=<OATH or YUBICO or STATIC>
        --yubislot=<1 or 2>
        --yubiCR                    : programm the Yubikey in challenge
                                      Response mode (TOTP, 60seconds)
    etokenng_mass_enroll [--label=TokenName]
    assigntoken:    --user --serial
    unassigntoken:  --serial
    importtoken:    --file or -f
    disabletoken:   --serial | --user
    enabletoken:    --serial | --user
    removeetoken:   --serial | --user
    resynctoken:    --serial | --user   --otp1  --otp2
    set:       [--user | --serial ] --pin --maxfailcount --syncwindow --otplen

    client machine commands
    ---------------------------
    createmachine:   --name [--ip]  [--desc]  [--decommission]
    deletemachine:   --name
    showmachine:     [--name]
    gettokenapps:   [--name] [--app] [--serial] [--challenge|--challenge_hex]
    
    The token-machine-binding is identified by the tuple (name, serial, app)
    
    machine_addtoken:   --name  --serial  --app
    machine_showtoken:  [--name] [--serial] [--app]
    machine_deltoken:   --name  --serial  --app
    
    machine_addoption:  --name  --serial  --app   --option
    machine_deloption:  --name  --serial  --app   --option
                        Note: You can specify several options like:
                        --option=slot=7 --option=partition=/dev/sda3

    Security Modules
    ----------------
    securitymodule:    get the status of the security module or set the
                       password for the module.
                       To set the password, you must specify the following
                       parameter:
                                   --module=<modulename>

    Server configuration
    --------------------
    getconfig:    returns the configuration of the privacyIDEA server
    setconfig:    sets a certain config value like this
                  --config='DefaultSyncWindow=500'
    Realm and resolver configuration
    --------------------------------
    getrealms:               lists all realms
    setrealm:        --realm=<realmname> --resolver=<resolverlist>
    deleterealm:     --realm=<realmname>
    setdefaultrealm: --realm=<realmname>
    getresolvers:            returns a list of all available resolvers
    deleteresolver:  --resolver=<resolvername>
    setresolver:     --resolver=<> --rtype=[LDAP,SQL,FILE] ....

  Parameters for commands:
    --csv             show the token list as CSV format
    --export_fields=<additional user fields> additional fields from the useridresolver to add to the export.
    --user=<user> or -u <user>
    --pin=<pin> or -p <pin>
    --serial=<S/N> or -s <serial>
    --description=<description for Token> or -d <description>
    --otpkey=<HMAC key> or -H
                      This is usually not necessary, as keys are read from the file
    --file=<file with Token data> or -f <file>
    --otpval=<otp value for resyncing>
    --window=<resyncing windows size> or -w
    --etng or -e
                      This parameter takes no value. If it is passed to the inittoken command,
                      an Aladdin eTokenNG OTP is initialized. --hmac and --serial are ignored.
    --pytoken         This parameter takes no value. This will create a soft Token as python script
                      example: privacyideaadm.py -U https://localhost -a admin -C inittoken --type=HMAC --pytoken --user=jdoe
    --type=<type> or -t
                      This specifies the Type of the OTP Token to be initialized.
                      HMAC is default. You may specify the type 'motp'
                      When using 'motp' you also need to specify --otppin=
    --realm=<realmname>
                      gives the realm to operate on.
    --resolver=<resolvername> or <resolverlist>
                      comma separated list of resolvers or
                      single resolver

  Parameters for the command setresolver:
    --rtype           Specify the type of the resolver: LDAP, SQL or FILE
                      Depending on the resolver type, there are different parameters to set.
    --rf_file         Resolver FILE: the filename containing the users on the privacyIDEA server
    --rl_uri          Resolver LDAP: the LDAP uri of the ldap server
    --rl_basedn       Resolver LDAP: the BaseDN for searching for users
    --rl_binddn       Resolver LDAP: the BindDN to authenticate to the LDAP server
    --rl_bindpw       Resolver LDAP: the Bind Password to authenticate to the LDAP server
    --rl_timeout      Resolver LDAP: the timeout when connecting to the LDAP server
    --rl_loginattr    Resolver LDAP: the attribute containing the loginname like uid
    --rl_searchfilter Resolver LDAP: the searchfilter. Something like (uid=*)(objectClass=inetOrgPerson)
    --rl_userfilter   Resolver LDAP: the userfilter for reverse resoling the DN for a given loginname,
                                     something like (&(uid=%s)(ObjectClass=inetOrgPerson))
    --rl_attrmap      Resolver LDAP: the attribute mapping. Something like:
                                     { "username": "uid", "phone" : "telephoneNumber", "groups" : "o", "mobile" : "mobile", "email" : "mail", "surname" : "sn", "givenname" : "givenName" }
"""


def options_to_dict(Option):
    '''
    This takes an array Option consisting of entries like
    slot=7, partition=dev3
    and converts it to a dictionary:
    { "option_slot": "7",
      "option_partition": "dev3" }
      
    :param Option: array of options
    :type Option: array
    :return: dictionary
    '''
    options = {}
    for option in Option:
        opt = option.split("=")
        if len(opt) == 2:
            # There was exactly one equal sign and we have a key and a value
            value = opt[1]
            if opt[0].startswith("option_"):
                key = opt[0]
            else:
                key = "option_" + opt[0]
            options[key] = value
    return options


def yubi_mass_enroll(lotpc,
                     proc_params,
                     yubi_mode,
                     yubi_slot,
                     yubi_prefix_serial,
                     yubi_prefix,
                     yubi_prefix_random,
                     yubi_cr):
    '''
    Do the Yubikey mass enrollment

    :param lotpc: the privacyidea connnection
    :param proc_params: the additional parameters from the command line
    :param yubi_mode: yubikey modus: YUBI_STATIC_MODE, YUBI_OATH_MODE, YUBI_AES_MODE
    :param yubi_slot: slot of the yubikey [1,2]
    :param yubi_prefix_serial: serial number added to the prefix
    :param yubi_prefix: the public prefix
    :param yubi_prefix_random: the rendom prefix
    :param yubi_cr: boolean - uses as TOTP token a.k.a. Challenge Response mode
    '''
    yp = YubikeyPlug()
    while 0 == 0:
        print "\nPlease insert the next yubikey.",
        sys.stdout.flush()
        submit_param = {}
        # input = raw_input("Please insert the next yubikey and press enter (x=Exit): ")
        # if "x" == input.lower():
        #    break
        _ret = yp.wait_for_new_yubikey()
        otpkey, serial = enrollYubikey(debug=False,
                                       APPEND_CR=not yubi_cr,
                                       prefix_serial=yubi_prefix_serial,
                                       fixed_string=yubi_prefix,
                                       len_fixed_string=yubi_prefix_random,
                                       slot=yubi_slot,
                                       mode=yubi_mode,
                                       challenge_response=yubi_cr)
        description = proc_params.get('description', "mass enrolled")
        if yubi_mode == YUBI_OATH_MODE:
            # According to http://www.openauthentication.org/oath-id/prefixes/
            # The OMP of Yubico is UB
            # As TokenType we use OM (oath mode)
            submit_param = {'serial': "UBOM%s_%s" % (serial, yubi_slot),
                            'otpkey': otpkey,
                            'description': description}
            if yubi_cr:
                submit_param['type'] = 'TOTP'
                submit_param['timeStep'] = 30

        elif yubi_mode == YUBI_STATIC_MODE:
            password = create_static_password(otpkey)
            # print "otpkey   ", otpkey
            # print "password ", password
            submit_param = {'serial': "UBSM%s_%s" % (serial, yubi_slot),
                            'otpkey': password,
                            'type': "pw",
                            'description': description}

        elif yubi_mode == YUBI_AES_MODE:
            yubi_otplen = 32
            if yubi_prefix_serial:
                yubi_otplen = 32 + len(serial) * 2
            elif yubi_prefix:
                yubi_otplen = 32 + (len(yubi_prefix) * 2)
            elif yubi_prefix_random:
                yubi_otplen = 32 + (yubi_prefix_random * 2)
            # According to http://www.openauthentication.org/oath-id/prefixes/
            # The OMP of Yubico is UB
            # As TokenType we use AM (AES mode)
            submit_param = {'type': 'yubikey',
                            'serial': "UBAM%s_%s" % (serial, yubi_slot),
                            'otpkey': otpkey,
                            'otplen': yubi_otplen,
                            'description': description}

        else:
            print "Unknown Yubikey mode"
            pass
        if 'realm' in proc_params:
            submit_param['realm'] = proc_params.get('realm')
        r1 = lotpc.inittoken(submit_param)
        showresult(r1)


def cifs_push(config, text):
    '''
    Push the the data text to a cifs share

    :param config: dictionary with the fields cifs_server, cifs_share, cifs_dir, cifs_user, cifs_password
    :type config: dict
    :param text: text to be pushed to the windows share
    :type text: string

    '''
    ret = False
    err = ""
    FILENAME = datetime.datetime.now().strftime("/tmp/%y%m%d-%H%M%S_privacyideaadm.out")
    f = open(FILENAME, 'w')
    f.write(text)
    f.close()

    filename = os.path.basename(FILENAME)

    print "Pushing %s to %s//%s/%s" % (filename,
                                       config.get("cifs_server"),
                                       config.get("cifs_share", ""),
                                       config.get("cifs_dir"))

    args = ["smbclient", "//%s\\%s" % (config.get("cifs_server"), config.get("cifs_share", "")),
            "-U", "%s%%%s" % (config.get("cifs_user"), config.get("cifs_password")), "-c",
            "put %s %s\\%s" % (FILENAME, config.get("cifs_dir", "."), filename) ]


    p = subprocess.Popen(args, cwd=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
    (result, error) = p.communicate()
    rcode = p.returncode
    print result
    print error

    try:
        os.remove(FILENAME)
    except Exception, e:
        print ("couldn't remove push test file: %r" % e)


def sendmail(config, text):
    '''
    Send an email with the text

    :param config: dictionary with the fields mail_from, mail_to, mail_host, mail_subject
    :type config: dict
    :param text: text to be sent via mail
    :type text: string

    '''
    if not config.get("mail_to"):
        Exception("mail_to required!")

    if not config.get("mail_host"):
        Exception("mail_host required!")

    print "sending mail to %s" % config.get("mail_to")
    msg = MIMEText(text)
    sender = config.get("mail_from")
    recipient = config.get("mail_to")
    msg['Subject'] = config.get("mail_subject")
    msg['From'] = sender
    msg['To'] = recipient

    s = smtplib.SMTP(config.get("mail_host"))
    s.sendmail(sender, [recipient], msg.as_string())
    s.quit()


def read_config(config_file):
    '''
    Read the configuration/parameters from a config file
    '''
    cfg = ConfigParser.SafeConfigParser()
    cfg_dict = {}
    cfg.read(config_file)
    for key, value in cfg.items("Default"):
        cfg_dict[key] = value

    return cfg_dict


##### main

def main():
    config = {"host": None,
              "command": None,
              "file": None,
              "admin": None,
              "password": None,
              "param": {},
              "etng": False,
              "pytoken": False,
              "certificate": None,
              "key": None,
              "protocol": "http",
              "authtype": "Digest",
              "yubi_prefix": None,
              "yubi_prefix_random": 0,
              "yubi_mode": YUBI_OATH_MODE,
              "yubi_slot": 1,
              "yubi_prefix_serial": False,
              "yubi_cr": False,
              "realm": None,
              "csv": False,
              "export_fields": None,
              "mail_from": "privacyidea@localhost",
              "mail_to": None,
              "mail_subject": "privacyIDEA notification",
              "mail_host": None
              }
    config_file = None
    _ask_password = None
    Option = []

    try:
        opts, _args = getopt(sys.argv[1:],
                             "hvU:a:C:k:c:f:u:s:p:d:ew:t:w:m:H:r:",
                             ["help", "version", "url=", "admin=", "cert=",
                              "key=", "command=", "file=",
                              "user=", "serial=", "pin=", "otpkey=",
                              "description=", "etng", "maxfailcount=",
                              "syncwindow=", "otplen=", "otp1=", "otp2=",
                              "pytoken", "type=", "otppin=",
                              "config=", 'realm=', 'resolver=', 'rtype=',
                              'module=', 'label=', 'authtype=', 'yubiprefix=',
                              'yubiprefixrandom=', 'yubimode=', 'yubislot=',
                              'yubiprefixserial', 'yubiCR', 'password=',
                              'csv', 'export_fields=', 'automate=', 'realm=',
                              'name=', 'ip=', 'desc=', 'decommission=', 'app=',
                              'challenge=', 'option=',
                              'challenge_hex='] + file_opts + ldap_opts)

    except GetoptError:
        print "There is an error in your parameter syntax:"
        usage()
        sys.exit(1)

# #### Creating Parameter list
    param = {}

    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage()
            sys.exit(0)
        elif opt in ('-U', '--url'):
            if arg.startswith('https://'):
                config["protocol"] = "https"
                config["host"] = arg[8:]
            elif arg.startswith('http://'):
                config["protocol"] = "http"
                config["host"] = arg[7:]
            else:
                print "Malformed url format. You need to start with http or https [" + arg + "]"
                sys.exit(1)
        elif opt in ('-a', '--admin'):
            config["admin"] = arg
            if _ask_password is None:
                # if _ask_password is already set to false, since it was specified, we must not set it
                _ask_password = True
        elif opt in ('--password'):
            config["password"] = arg
            _ask_password = False
        elif opt in ('-c', '--cert'):
            config["certificate"] = arg
        elif opt in ('-k', '--key'):
            config["key"] = arg
        elif opt in ('-C', '--command'):
            config["command"] = arg
        elif opt in ('-f', '--file'):
            config["file"] = arg
        # user, serial (needed for assigntoken)
        elif opt in ('-u', '--user'):
            param['user'] = arg
        elif opt in ('-s', '--serial'):
            param['serial'] = arg
        # pin, hmac, description (needed for inittoken)
        elif opt in ('-p', '--pin'):
            param['pin'] = arg
        elif opt in ('-H', '--otpkey'):
            param['otpkey'] = arg
        elif opt in ('-m', '--maxfailcount'):
            param['maxfailcount'] = arg
        elif opt in ('-w', '--window'):
            param['syncwindow'] = arg
        elif opt in ('--otplen'):
            param['otplen'] = arg
        elif opt in ('--otp1'):
            param['otp1'] = arg
        elif opt in ('--otp2'):
            param['otp2'] = arg
        elif opt in ('-d', '--description'):
            param['description'] = arg
        elif opt in ('--label'):
            param['label'] = arg
        elif opt in ('--etng'):
            if EDITION == "EE":
                config["etng"] = True
        elif opt in ('--pytoken'):
            config["pytoken"] = True
        elif opt in ('-t', '--type'):
            param['type'] = arg
        elif opt in ('--otppin'):
            param['otppin'] = arg
        elif opt in ('-v', '--version'):
            print "privacyideaadm.py " + VERSION
            sys.exit(0)
        elif opt in ('--config'):
            key, value = arg.rsplit('=', 2)
            param[key] = value
        elif opt in ('--realm'):
            param['realm'] = arg
        elif opt in ('--resolver'):
            param['resolver'] = arg
        elif opt in ('--rtype'):
            param['rtype'] = arg

        elif opt in ('--rf_file'):
            param['rf_file'] = arg
        elif opt in ('--authtype'):
            config["authtype"] = arg
        elif opt in ('--module='):
            param['module'] = arg
        elif opt in ('--yubiprefix='):
            config["yubi_prefix"] = arg
        elif opt in ('--yubiprefixrandom='):
            config["yubi_prefix_random"] = int(arg)
        elif opt in ('--yubimode='):
            if arg.lower() == "yubico":
                config["yubi_mode"] = YUBI_AES_MODE
            elif arg.lower() == "static":
                config["yubi_mode"] = YUBI_STATIC_MODE
            else:
                print "Using OATH as default."
        elif opt in ('--yubislot='):
            config["yubi_slot"] = int(arg)
        elif opt in ('--yubiprefixserial'):
            config["yubi_prefix_serial"] = True
        elif opt in ('--yubiCR'):
            config["yubi_cr"] = True

        elif opt in ('--csv'):
            config["csv_format"] = True
        elif opt in ('--export_fields='):
            config["export_fields"] = arg
        elif opt in ('--automate='):
            config_file = arg
        elif opt in ('--realm='):
            param["realm"] = arg
        elif opt in ('--ip='):
            param["ip"] = arg
        elif opt in ('--name='):
            param["name"] = arg
        elif opt in ('--decommission='):
            param["decommission"] = arg
        elif opt in ('--desc='):
            param["desc"] = arg
        elif opt in ('--app='):
            param["app"] = arg
        elif opt in ('--challenge='):
            param["challenge"] = arg
        elif opt in ('--challenge_hex='):
            param["challenge_hex"] = arg
        elif opt in ('--option='):
            Option.append(arg)

        for l_opt in ldap_opts:
            o = l_opt.split('=')
            if opt in ("--%s" % o[0]):
                param[o[0]] = arg

    if _ask_password:
        config["password"] = getpass.getpass(prompt="Please enter password for"
                                                    " '%s':" % config["admin"])

    if config_file:
        config_from_file = read_config(config_file)
        config.update(config_from_file)

    if not (config["host"] and config["command"]):
        print "Missing arguments. See --help"
        usage()
        sys.exit(0)

    if config["command"] not in COMMANDS:
        print "Unknown command. See --help"
        usage()
        sys.exit(0)

    # Create the privacyideaclient instance
    lotpc = privacyideaclient(config.get("protocol"),
                              config.get("host"),
                              admin=config.get("admin"),
                              adminpw=config.get("password"),
                              cert=config.get("certificate"),
                              key=config.get("key"),
                              authtype=config.get("authtype"))

# #### The commands

    if (config.get("command") == "listtoken"):
        # TODO: at the moment we support the export to cifs share or sending
        #       by mail only
        #       for the command "listtoken". The should be refactored one day.
        if config.get("csv_format"):
            param['outform'] = 'csv'
            if config.get("export_fields"):
                param['user_fields'] = config.get("export_fields")
            r1 = lotpc.connect('/admin/show', {}, param, json_format=False)
            if config.get("mail_host") and config.get("mail_to"):
                sendmail(config, r1)
            if config.get("cifs_server") and config.get("cifs_user") and config.get("cifs_password"):
                cifs_push(config, r1)
        else:
            r1 = lotpc.listtoken(param)
            result = r1['result']

            tabsize = [4, 16, 14, 20, 20, 4, 4, 4, 4]
            tabstr = ["%4s", "%16s", "%14s", "%20s", "%20s", "%4s", "%4s", "%4s", "%4s", "%4s"]
            tabdelim = '|'
            tabvisible = [0, 1, 2, 3, 4, 5, 6, 7, 8]
            tabhead = ['Id', 'Desc', 'S/N', 'User', 'Resolver', 'MaxFail', 'Active', 'FailCount', 'Window']
            tabentry = ['privacyIDEA.TokenId',
                        'privacyIDEA.TokenDesc',
                        'privacyIDEA.TokenSerialnumber',
                        'User.username',
                        'privacyIDEA.IdResClass',
                        'privacyIDEA.MaxFail',
                        'privacyIDEA.Isactive',
                        'privacyIDEA.FailCount',
                        'privacyIDEA.SyncWindow']
            dumpresult(result['status'],
                       result['value']['data'],
                       {'tabsize': tabsize,
                        'tabstr': tabstr,
                        'tabdelim': tabdelim,
                        'tabvisible': tabvisible,
                        'tabhead': tabhead,
                        'tabentry': tabentry})
    elif (config.get("command") == "listuser"):
        r1 = lotpc.userlist({'username': '*'})
        result = r1['result']
        tabentry = ['username',
                    'surname',
                    'userid',
                    'phone',
                    'mobile',
                    'email']
        tabsize = [20, 20, 20, 20, 20, 20]
        tabstr = ["%20s", "%20s", "%20s", "%20s", "%20s", "%20s"]
        tabdelim = '|'
        tabvisible = [0, 1, 2, 3, 4, 5]
        tabhead = ['login', 'surname', 'Id', 'phone', 'mobile', 'email']
        dumpresult(result['status'], result['value'], { 'tabsize' : tabsize, 'tabstr' : tabstr,
                    'tabdelim' : tabdelim, 'tabvisible': tabvisible,
                    'tabhead' : tabhead, 'tabentry' : tabentry })
    elif (config.get("command") == "getconfig"):
        r1 = lotpc.readserverconfig({})
        showresult(r1)
    elif (config.get("command") == "setconfig"):
        print param
        r1 = lotpc.writeserverconfig(param)
        showresult(r1)
    elif (config.get("command") == "assigntoken"):
        if 'user' not in param or 'serial' not in param:
            print "To assign a token, we need a username and a tokenserial:"
            print "   --command=assigntoken --user=<username> --serial=<tokenserial>"
            sys.exit(1)
        r1 = lotpc.assigntoken(param)
        showresult(r1)
    elif (config.get("command") == "unassigntoken"):
        if 'serial' not in param:
            print "To unassign a token, we need a tokenserial:"
            print "   --command=unassigntoken --serial=<tokenserial>"
            sys.exit(1)
        r1 = lotpc.unassigntoken(param)
        showresult(r1)
    elif (config.get("command") == "yubikey_mass_enroll"):
        yubi_mass_enroll(lotpc, param,
                         config.get("yubi_mode"),
                         config.get("yubi_slot"),
                         config.get("yubi_prefix_serial"),
                         config.get("yubi_prefix"),
                         config.get("yubi_prefix_random"),
                         config.get("yubi_cr"))

    elif (config.get("command") == "etokenng_mass_enroll"):
        print "Mass-Enrolling eToken NG OTP. Beware the tokencontents of all tokens will be deleted."
        print "Random User PINs and SO-PINs will be set. The SO-PIN will be stored in the Token-Database."
        print
        while 0 == 0:
            answer = raw_input("Please insert the next eToken NG and press enter (x=Exit): ")
            if "x" == answer.lower():
                break
            tokenlabel = param.get('label', "privacyIDEAToken")
            description = param.get('description', 'eTokenNG mass enrolled')
            tdata = initetng({'label': tokenlabel,
                              'debug': False,
                              'description': description})
            if not tdata['userpin'] or not tdata['hmac'] or not tdata['serial']:
                print "No token was added to privacyIDEA:", tdata['error']
                sys.exit(1)
            param['serial'] = tdata['serial']
            param['otpkey'] = tdata['hmac']
            param['userpin'] = tdata['userpin']
            param['sopin'] = tdata['sopin']
            r1 = lotpc.inittoken(param)
            showresult(r1)

    elif (config.get("command") == "inittoken"):
        if etng:
            tokenlabel = param.get('user',
                                   param.get('label', "privacyIDEAeToken"))
            tdata = initetng({'label': tokenlabel,
                              'debug': True})
            if not tdata['userpin'] or not tdata['hmac'] or not tdata['serial']:
                print "No token was added to privacyIDEA: ", tdata['error']
                sys.exit(1)
            param['serial'] = tdata['serial']
            param['otpkey'] = tdata['hmac']
            param['userpin'] = tdata['userpin']
            param['sopin'] = tdata['sopin']
            print "FIXME: what shall we do with the eToken password and SO PIN: ", tdata['userpin'], tdata['sopin']
        elif config.get("pytoken"):
            if 'user' not in param:
                print "To initialize a pyToken, please provide a username"
                sys.exit(1)
            pyTemplate = "FAIL"
            pyTemplateList = ('pytoken.template.py',
                              '/usr/share/pyshared/privacyideautils/pytoken.template.py',
                              '/usr/local/lib/python2.6/dist-packages/privacyideautils/pytoken.template.py',
                              '/usr/lib/python2.6/dist-packages/privacyideautils/pytoken.template.py',
                              )
            for pT in pyTemplateList:
                if os.path.isfile(pT):
                    pyTemplate = pT
                    break
            if pyTemplate == "FAIL":
                print "Could not find any pytoken template!"
                sys.exit(1)
            else:
                pyTok = pyToken(keylen=256, template=pyTemplate)
                pyTokenfile = pyTok.createToken(param['user'])
                param['otpkey'] = pyTok.getHMAC()
                param['serial'] = pyTok.getSerial()
                print pyTokenfile
        else:
            if 'user' not in param or 'serial' not in param or 'otpkey' not in param:
                print "To initialize a token, we need at least a username, a tokenserial and an OTPkey/HMAC:"
                print "   --command=inittoken --user=<username> --serial=<tokenserial> --hmac=<HMAC>"
                sys.exit(1)
        r1 = lotpc.inittoken(param)
        showresult(r1)
    elif (config.get("command") == "importtoken"):
        if not file:
            print "To import tokens, we need a filename!"
            sys.exit(1)
        lotpc.importtoken ({'file': file})
    elif (config.get("command") == "disabletoken"):
        r1 = lotpc.disabletoken(param)
        showresult(r1)
    elif (config.get("command") == "removetoken"):
        r1 = lotpc.removetoken(param)
        showresult(r1)
    elif (config.get("command") == "enabletoken"):
        r1 = lotpc.enabletoken(param)
        showresult(r1)
    elif (config.get("command") == "resynctoken"):
        r1 = lotpc.resynctoken(param)
        showresult(r1)
    elif (config.get("command") == "set"):
        if 'user' not in param and 'serial' not in param:
            print "Please provide either or user or a serial to set the pin."
            sys.exit(1)
        r1 = lotpc.set(param)
        showresult(r1)
    elif (config.get("command") == "getrealms"):
        r1 = lotpc.getrealms({})
        showresult(r1)
    elif (config.get("command") == "setrealm"):
        if "realm" not in param or "resolver" not in param:
            print "You need to provide a realm and resolvers."
            sys.exit(1)
        param['resolvers'] = param['resolver']
        r1 = lotpc.setrealm(param)
        showresult(r1)
    elif (config.get("command") == "deleterealm"):
        if "realm" not in param:
            print "You need to provide a realm."
            sys.exit(1)
        r1 = lotpc.deleterealm(param)
        showresult(r1)
    elif (config.get("command") == "securitymodule"):
        r1 = {}
        if "module" in param:
            password = getpass.getpass(prompt="Please enter password for security module '%s':" % param["module"])
            print "Setting the password of your security module %s" % param['module']
            r1 = lotpc.securitymodule(param={"hsm_id": param["module"],
                                             "password": str(password)})
        else:
            print "This is the configuration of your active Security module:"
            print
            r1 = lotpc.securitymodule(param={})
        showresult(r1)
    elif (config.get("command") == "setdefaultrealm"):
        if "realm" not in param:
            print "You need to provide a realm."
            sys.exit(1)
        r1 = lotpc.setdefaultrealm(param)
        showresult(r1)
    elif (config.get("command") == "getresolvers"):
        r1 = lotpc.getresolvers({})
        showresult(r1)
    elif (config.get("command") == "deleteresolver"):
        if "resolver" not in param:
            print param
            print "You need to provide a resolver."
            sys.exit(1)
        r1 = lotpc.deleteresolver(param)
    elif (config.get("command") == "setresolver"):
        if "rtype" not in param:
            print "your need to specify a type of the resolver."
            sys.exit(1)
        if param['rtype'] == 'LDAP':
            for opt in ldap_opts:
                o = opt.split('=')
                if o[0] not in param:
                    print "you need to specify --%s for ldap resolvers" % o[0]
                    sys.exit(1)
        elif param['rtype'] == 'SQL':
            print "TODO: SQL parameters not implemented yet"
            sys.exit(1)
        elif param['rtype'] == 'FILE':
            if 'rf_file' not in param:
                print "you need to specify --rf_file!"
                sys.exit(1)
        r1 = lotpc.setresolver(param)
        showresult(r1)
    elif (config.get("command") == "loadtokens"):
        filename = 'plain-value-pskc.xml'
        f = open(filename, 'r')
        xml_data = f.read()
        ret = lotpc.connect("/admin/loadtokens",
                            {},
                            {'type': 'pskc',
                             'file': xml_data,
                             'pskc_type': 'plain',
                             'pskc_password': None,
                             'pskc_preshared': None})
        showresult(ret)

    elif (config.get("command") == "createmachine"):
        ret = lotpc.connect("/machine/create", {},
                            {"name": param.get("name"),
                             "ip": param.get("ip", ""),
                             "desc": param.get("desc", "")})
        showresult(ret)
    elif (config.get("command") == "showmachine"):
        ret = lotpc.connect("/machine/show",
                            {},
                            {"name": param.get("name")} if param.get("name") else {})
        showresult(ret)
    elif (config.get("command") == "gettokenapps"):
        tokenapps_param = {}
        if param.get("name"):
            tokenapps_param["name"] = param.get("name")
        if param.get("app"):
            tokenapps_param["application"] = param.get("app")
        if param.get("serial"):
            tokenapps_param["serial"] = param.get("serial")
        if param.get("challenge"):
            # the controller requires the challenge to be in hex
            tokenapps_param["challenge"] = binascii.hexlify(param.get("challenge"))
        elif param.get("challenge_hex"):
            tokenapps_param["challenge"] = param.get("challenge_hex")
        print "calling with %r" % tokenapps_param
        ret = lotpc.connect("/machine/gettokenapps", {}, tokenapps_param)
        showresult(ret)
    elif (config.get("command") == "deletemachine"):
        if param.get("name"):
            ret = lotpc.connect("/machine/delete",
                                {},
                                {"name": param.get("name")})
            showresult(ret)
        else:
            print "You need to specify a --name!"
    elif (config.get("command") == "machine_addtoken"):
        m_params = {"name": param.get("name"),
                    "serial": param.get("serial"),
                    "application": param.get("app")}
        ret = lotpc.connect("/machine/addtoken",
                            {},
                            m_params)
        showresult(ret)
        if len(Option) > 0:
            options = options_to_dict(Option)
            ret = lotpc.connect("/machine/addoption",
                                {},
                                dict(m_params.items() + options.items()))
            showresult(ret)
    elif (config.get("command") == "machine_showtoken"):
        p = {}
        for key in ["name", "serial", "app"]:
            if param.get(key):
                p[key] = param.get(key)
        
        ret = lotpc.connect("/machine/showtoken", {}, p)
        showresult(ret)
    elif (config.get("command") == "machine_deltoken"):
        ret = lotpc.connect("/machine/deltoken",
                            {},
                            {"name": param.get("name"),
                             "serial": param.get("serial"),
                             "application": param.get("app")})
        showresult(ret)
    elif (config.get("command") == "machine_addoption"):
        m_params = {"name": param.get("name"),
                    "serial": param.get("serial"),
                    "application": param.get("app")}
        if len(Option) > 0:
            options = options_to_dict(Option)
            ret = lotpc.connect("/machine/addoption",
                                {},
                                dict(m_params.items() + options.items()))
            showresult(ret)
    elif (config.get("command") == "machine_deloption"):
        m_params = {"name": param.get("name"),
                    "serial": param.get("serial"),
                    "application": param.get("app")}
        if len(Option) > 0:
            options = options_to_dict(Option)
            for key in options.keys():
                ret = lotpc.connect("/machine/deloption",
                                    {},
                                    dict({"key": key}.items() + m_params.items()))
                showresult(ret)
    else:

        print "Nothing to do and nothing done."


if __name__ == '__main__':
    print
    print "Deprecation Warning! This command will be removed in version 1.4!"
    print
    main()
    print
    print "Deprecation Warning! This command will be removed in version 1.4!"
    print
