From 4326f9ced3e4c9ff498f2c710bda2b2f89fe284c Mon Sep 17 00:00:00 2001
From: Peter Gietz <peter@daasi.de>
Date: Fri, 16 Dec 2011 13:17:31 +0000
Subject: [PATCH] Initial Cechin of the version with proxy rewrite path feature

git-svn-id: https://textgridlab.org/svn/textgrid/trunk/middleware/tgauth@11703 7c539038-3410-0410-b1ec-0f2a7bf1c452
---
 .../etc/pwReset.conf                          |    0
 .../etc/pwReset.css                           |    0
 .../etc/pwReset.sys                           |  428 +++++++
 .../etc/pwReset.sys~                          |  417 +++++++
 .../pwReset.pl                                | 1062 +++++++++++++++++
 .../svn-commit.tmp                            |    5 +
 6 files changed, 1912 insertions(+)
 create mode 100644 info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.conf
 create mode 100644 info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.css
 create mode 100644 info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys
 create mode 100644 info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys~
 create mode 100755 info.textgrid.middleware.tgauth.passwordReset/pwReset.pl
 create mode 100644 info.textgrid.middleware.tgauth.passwordReset/svn-commit.tmp

diff --git a/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.conf b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.conf
new file mode 100644
index 0000000..e69de29
diff --git a/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.css b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.css
new file mode 100644
index 0000000..e69de29
diff --git a/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys
new file mode 100644
index 0000000..9697c50
--- /dev/null
+++ b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys
@@ -0,0 +1,428 @@
+#reading file /usr/local/src/devel/IdM/pwReset/etc/pwReset-unclean.sys
+
+progname = "pwReset"
+
+version = 0.1
+
+date = "2011-01-11"
+<author>
+   name  = "Peter Gietz" 
+   org= "DAASI International GmbH"
+   mail = "peter.gietz@daasi.de"
+</author>
+
+<copyright>
+text1 = Copyright (c) 2005 DAASI International GmbH
+text2 = This library is free software; you can redistribute it and/or \
+modify it under the same terms as Perl itself.
+</copyright>
+
+progshortdescr = "Webtool for password reset"
+
+<progdescription>
+text1 ="pwReset is a simple webtool for password reset. It works as follows: \
+When first started (status = 'none') it tests whether cookies are enabled \
+(via redirect to status testcookie), and returns a respective message to the \
+user if not, with a link to start all over again." 
+text2 = "If the cookie is \
+retrievable an Apache-session is established (information is stored in files \
+on the server) and a mask is shown to the user, where she can input an ID \
+(loginid, email address or TextGrid ID). If mode 'oneinputfield' is set in the \
+configuration there is one input field for either of them, if not, there are \
+three separate input fields."
+text3 = "After pressing the \"verify me\" button the programm is called with \
+'sendlink' status where the programm first checks whether the input values \
+conform to configurable regular expressions \
+(e.g. \".*\\@.*\" for email address), \
+returns respective errors if they do not conform. If they do, the programm \
+looks up the ID in the LDAP server and retrieves an email address from there \
+(even if the ID was the mail address). \
+If the ID was found a separate sessionid (not the ID in the cookie) is created \
+and concatenated to an url that calls status 'printform' and that url is sent \
+to the email address with some configurable text."
+text4 = "If the user clicks on the url in that email, the sessionid in the \
+query is compared with the respective id stored in the session and if they \
+are identical a form to input the password (in two separate input fields) is \
+displayed. After pressing the button \"reset password\" the program is \
+restarted with the status 'modify'."
+text5 = "In this last status again the matching of sessionid is checked, as \
+well as the matching of password and retyped password. Then it is checked how \
+often the session has been used (there is a counter for every access) and \
+whether that number is less than a configurable maximum. The password value is \
+then tested against the configurable regular expression that defines the \
+password policy. If any of these checks fail a respective error message is \
+displayed, otherwise the program looks up the entry and changes the password \
+in the LDAP server."
+text6 = "At any error state, the user either gets the last input screen (e.g. \
+when wrong values have been inputted) or a link to restart the process (e.g. if \
+session is not valid any more). A lot of things are configurable (see the \
+single options below). HTTPS as well as TLS for the LDAP connection can be \
+enforced. All activities can be logged. Configuration concerning input fields \
+(labels, regExp, etc.) happens in a hash at the beginning of the source code. \
+Everything else can be configured in a Apache style configuration file. All \
+passwords needed (for LDAP access and for SMTP auth) are sored in a separate \
+file."
+text7= "If you start the program with status 'adminhelp' \
+(/url/?status=adminhelp) this manpage is displayed in the browser. You can \
+additionally specify one single configuration option to only have the help to \
+that option displayed (e.g. /url/?status=adminhelp&helpfeature=emailconfig). \
+The adminhelp feature can be turned off in the configuration."  
+
+</progdescription>
+ 
+
+<bugs>
+text1 = "Please report bugs to peter.gietz@daasi.de"
+text2 = "some todos are: "
+text3 = "more than one regExp per inputfield"
+text4 = "multilanguage support is already designed but needs gettext translations"
+text5 = "configurable css file does not work properly yet"
+</bugs>
+
+<additions example>
+text1 = "For getting this manpage: "
+text2 = "   pwReset.pl -h"
+text3 = " "
+</additions>
+
+<additions requirements>
+text1 = "Following modules are required: "
+text2 = "* Config::General"
+text5 = "* File::Basename"
+text6 = "* File::Copy"
+text7 = "* File::Flock"
+text8 = "* File::Temp"
+text9 = "* Getopt::Std"
+text10 = "* IO::Prompt"
+text11 = "* Log::Log4perl"
+text12 = "* LWP::Authen::Ntlm"
+text13 = "* MIME::Base64"
+text14 = "* Net::LDAP"
+text15 = "* Net::SMTP"
+text18 = "* Text::Wrap"
+</additions>
+
+<options loglevel>
+        key = "l"
+        must = 0
+        description = "Loglevel for controlling logmessages."
+	description_de = "Loglevel zur Kontrolle des Logging."
+        arg = 1
+        argtype = "skalar"
+	values = "no, all, debug, info, warn, error, fatal" 
+        default = "warn"
+</options>
+
+<options logfile>
+        key = "L"
+        must = 0
+        description = "Name of the logfile with absolute or relative path. "
+	description_de = "Name der Logdatei mit absolutem oder relativem Pfad." 
+        arg = 1
+        argtype = "filename_add_subdir_log"
+        default = "pwReset.log"
+</options>
+
+<options debugmode>
+        key = "d"
+        must = 0
+        description = "Sets debug mode to on."
+        description_de = "Stellt den Debug-Modus an."
+        arg = 0
+</options>
+
+<options verbose>
+        key = "v"
+        must = 0
+        description = "Sets verbose mode which makes the program quite chatty."
+        description_de = "Stellt den Verbose-Modus an, womit das Programm \
+        gespraechiger wird."
+        arg = 0
+</options>
+
+<options language>
+        key = "G"
+        must = 0
+        description = "Sets the language for output like this one"
+        description_de = "Setzt die Sprache fuer Ausgaben wie diese. "
+        arg = 1
+	default = en
+	values = en, de
+</options>
+
+<options passwordfile>
+        key = "p"
+        description = "Name of the password file which contains the secrets \
+		    the programm must know to connect to data bases etc. \
+		    The format for all lines of this file must be: \
+		    <token><blank><password> where <token> has to be the \
+		    option label which defines the database such as e.g. \
+                    \"outputuri\". "
+        description_de = "Name einer Datei, welche die Passworte enthaelt, \
+		    die das Programm wissen muss um Datenbanken zu \
+		    kontaktieren etc. Das Format dieser Datei ist: \
+		    <Token><Leerzeichen><Passwort> wobei <Token> ein \
+		    Optionsname sein muss, welcher die Datenbank \
+		    definiert wie z.B. \"outputuri\". "
+        arg = 1
+	default = "pwReset.secret"
+        argtype = "filename_exist"
+</options>
+
+<options configfile>
+        key = "c"
+        must = 0
+        description = Name of the user config file with absolute or \
+		    relative path."
+        description_de = Name der benutzerdefinierten Konfigurationsdatei \
+		    mit absolutem oder relativem Pfad."
+        arg = 1
+        argtype = "filename_exist_subdir_etc"
+        default = "./etc/pwReset.conf"
+</options>
+
+
+<options printhelp>
+        key = "h"
+        must = 0
+        description = "prints out the manpage"
+        description_de = "Druckt die Manpage aus"
+        arg = 0
+</options>
+
+
+<options helpfeature>
+        key = "H"
+        must = 0
+        description = "prints out description of the feature referenced by \
+	    commandline flag or config file token. "
+        description_de = "Druckt die Beschreibung der Option aus, die \
+	    entweder ueber den Kommandozeilen- oder ueber den \
+	    Konfigurationsdatei-Parameter spezifiziert wird."
+        arg = 1
+</options>
+
+
+<options emailconfig>
+        key = "e"
+        must = 0
+        description = "specifies the SMTP-communication of the program, in a \
+	        string with token-value pairs, format: \
+		\#token1=value1;\#token2=value; etc. \
+		Following tokens are understood: \
+		\#smtprelay sets the mailserver from which the mail should \
+		be sent \
+		\#from sets the from address of the mail to be sent. \
+		\#to sets the mailaddress of the administrator to whom mails \
+		should be sent. More than one address can be separated by \
+		comma. \
+		\#subjectpart sets a prefix that will be included in the \
+		subject line.\n\
+		\#hello sets the smtpclient name.\n\
+		\#smtpuser sets the user name SMTP Auth authentication. \
+ 		In this case the corresponding password has to \
+		be stored in the passwordfile (-p, default is \
+		dbconnector.secret) behind the token smtpauth."
+         description_de = "Spezifiziert das Mail-Interface des Programms \
+	        wodurch in bestimmten Faellen automatische E-Mails an den \
+		Administrator geschickt werden koennen. Das Format besteht \
+		aus mit Semikolon getrennten Schluessel-Wert-Paaren, wobei \
+		der Schluessel mit einem vorgestellten \# gekennzeichnet \
+		wird: \n\
+		\#token1=value1;\#token2=value; etc. \n\
+		Folgende Tokens werden unterstuetzt: \n\
+		\#smtprelay spezifiziert den Mailserver von welchem aus die \
+		Mail geschickt werden soll.\n\
+		\#from spezifiziert die Sender-E-Mail-Adresse.\n\
+		\#to spezifiziert die Ziel-Adresse des Administratoren, an \
+		den die automatischen Mails geschickt werden sollen. \
+		Hierbei koennen mehrere mit Komma separierte Adressen \
+		angegeben werden.\n\
+		\#subjectpart setzt ein Praefix fuer die verschiedenen \
+		Mail-Subjects.\n\
+		\#hello setzt den smtpclient-Namen.\n\
+		\#smtpuser setzt den User-Namen für SMTP \
+		Auth-Authentifizierung. Wenn dieser gesetzt ist, muss \
+ 		das korrespondierende Passwort in der mit \
+		passwordfile spezifizierten Datei (-p, Voreinstellung \
+		ist dbconnector.secret) hinter dem Stichwort smtpauth \
+		eingetragen sein."
+        arg = 1
+	argtype = token_emailinfo
+        default = 0
+</options>
+
+<options cssfile>
+        key = "C"
+        must = 0
+        description = "Name of the CSS file with absolute or \
+		    relative path."
+        description_de = "Name der CSS-Datei \
+		    mit absolutem oder relativem Pfad."
+        arg = 1
+        argtype = "filename_exist_subdir_etc"
+        default = "./etc/pwReset.css"
+</options>
+
+<options sessionpath>
+        key = "s"
+        must = 0
+        description = "Path (relative or absolute) of the directory where to store session information."
+        description_de = "Pfad (relativ oder absolut) zum Verzeichnis, in dem die Session-Informationen gespeichert werden."
+        arg = 1
+        argtype = "filename_dir"
+        default = "./sessions"
+</options>
+
+<options sessionlockpath>
+        key = "S"
+        must = 0
+        description = "Path (relative or absolute) of the directory where to store session lock information."
+        description_de = "Pfad (relativ oder absolut) zum Verzeichnis, in dem die Session-Lock-Informationen gespeichert werden."
+        arg = 1
+        argtype = "filename_dir"
+        default = "./locks"
+</options>
+
+<options sessiontime>
+        key = "T"
+        must = 0
+        description = "Sets the duration of a cookie session. Format: +<number><unit>, where you can specify the following units:  s for seconds, m for minutes, h for hours, d for days, M for months, and y for years"
+        description_de = "definiert die Lebensdauer einer cookie session. Format: +<Nummer><Einheit>, wobei Einheit s für Sekunden, m für Minuten, h für Stunden, d für Tage, M für Monate, und y für Jahre steht. "
+        arg = 1
+	default = "2d"
+</options>
+
+
+<options title>
+        key = "t"
+        must = 1
+        description = "Sets the page title."
+        description_de = "definiert den Seitentitel."
+        arg = 1
+	default = "Password Reset Tool"
+</options>
+
+<options charset>
+        key = "X"
+        must = 1
+        description = "Sets the character set."
+        description_de = "definiert die Zeichensatzkodierung."
+        arg = 1
+	default = "utf-8"
+	values = "utf-8, iso5889" 
+</options>
+
+<options bgcolor>
+        key = "b"
+        must = 0
+        description = "Sets the background color"
+        description_de = "definiert die Hintergrundsfarbe."
+        arg = 1
+	default = "ffffff"
+</options>
+
+<options linkmail>
+        key = "K"
+        must = 0
+        description = "Sets the text for the link mail"
+        description_de = "Definiert die link mail"
+        arg = 1
+	default = "You receive this message, because someone (probably you) requested $ to reset your Password. $ You can do this with following link: %URL%"
+</options>
+
+
+<options meta>
+        key = "M"
+        must = 0
+        description = "Sets the metatags. Format: name1:content1|name2:content2"
+        description_de = "definiert die Meta-Tags. \
+	 Format: name1:content1|name2:content2"
+        arg = 1
+	default = "Robots:noindex,nofollow"
+</options>
+
+<options ldapuri>
+        key = "u"
+        must = 1
+        description = "URI for input of LDAP data. \n\
+		    The format for the LDAP URI is (see RFC 4516): \
+		    ldap://<host>[:<port>]/<basedn>?<attributes>?<scope>?\n\
+		    <filter>?<extension> where <extension> can by now only \
+		    be either bindname=<bindname> for authenticating to the \
+		    server. In this case the corresponding password has to \
+		    be stored in the passwordfile (-p, default is \
+		    dbconnector.secret) behind the token inputuri. \
+		    The second extension supported is \
+		    config=<Slapd-configuration file>, which is only \
+		    needed with inputformat _REPL."
+        description_de = "URI fuer Eingabedaten aus einem LDAP-Server.\n\
+		    Das Format fuer die LDAP-URI (siehe RFC 4516) ist: \
+		    ldap://<host>[:<port>]/<basedn>?<attributes>?<scope>?\n\
+		    <filter>?<extension> wobei als <extension> gegenwaertig \
+		    folgende Erweiterungen unterstuetzt werden:\n\
+		    bindname=<bindname> zur Authentifizierung am Server, \
+		    wobei das korrespondierende Passwort in der mit \
+		    passwordfile spezifizierten Datei (-p, Voreinstellung \
+		    ist dbconnector.secret) hinter dem Stichwort inputuri \
+		    eingetragen sein muss.\n\
+		    config=<Slapd-configuration file>, womit die zu \
+		    verwendende Open-LDAP-Konfigurationsdatei spezifiziert \
+		    wird, was nur im Zusammenhang mit dem inputformat (-I) \
+		    \"_REPL\" benoetigt wird."
+        arg = 1
+        argtype = "uri"
+</options>
+
+<options pwhash>
+        key = "P"
+        must = 1
+        description = "Specifies the password hash algorithm"
+        description_de = "definiert den Passwort-Hash-Algorhitmus"
+        arg = 1
+	default = "SSHA"
+	values = "SSHA, MD5, CRYPT"
+</options>
+
+<options forcehttps>
+        key = "f"
+        must = 0
+        description = "Forces https."
+        description_de = "Erzwingt https."
+        arg = 0
+</options>
+
+<options oneinputfield>
+        key = "o"
+        must = 0
+        description = "Combines all ID-inputfields to one and creates a complex filter"
+        description_de = "vereinigt alle ID-Eingabefelder in eins und baut entsprechende Filter auf"
+        arg = 0
+</options>
+
+<options forcetls>
+        key = "z"
+        must = 0
+        description = "Forces START_TLS in LDAP-connection"
+        description_de = "Erzwingt START_TLS in LDAP-Verbindung"
+        arg = 0
+</options>
+
+
+<options rewritepath>
+        key = "r"
+        must = 0
+        description = "Rewrites path, which might be needed for proxying. \
+	Format: <regexp>=><string>;<regexp>=><string>;..."
+        description_de = "Schreibt den Pfad um, was bei Proxying notwendig \
+	sein kann. Format: <regexp>=><string>;<regexp>=><string>;..."
+        arg = 0
+</options>
+
+<options enableadminhelp>
+        key = "a"
+        must = 0
+        description = "Allows display of adminhelp"
+        description_de = "Erlaubt die Anzeige der Admin-Hilfe"
+        arg = 0
+</options>
diff --git a/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys~ b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys~
new file mode 100644
index 0000000..73546dc
--- /dev/null
+++ b/info.textgrid.middleware.tgauth.passwordReset/etc/pwReset.sys~
@@ -0,0 +1,417 @@
+#reading file /usr/local/src/devel/IdM/pwReset/etc/pwReset-unclean.sys
+
+progname = "pwReset"
+
+version = 0.1
+
+date = "2011-01-11"
+<author>
+   name  = "Peter Gietz" 
+   org= "DAASI International GmbH"
+   mail = "peter.gietz@daasi.de"
+</author>
+
+<copyright>
+text1 = Copyright (c) 2005 DAASI International GmbH
+text2 = This library is free software; you can redistribute it and/or \
+modify it under the same terms as Perl itself.
+</copyright>
+
+progshortdescr = "Webtool for password reset"
+
+<progdescription>
+text1 ="pwReset is a simple webtool for password reset. It works as follows: \
+When first started (status = 'none') it tests whether cookies are enabled \
+(via redirect to status testcookie), and returns a respective message to the \
+user if not, with a link to start all over again." 
+text2 = "If the cookie is \
+retrievable an Apache-session is established (information is stored in files \
+on the server) and a mask is shown to the user, where she can input an ID \
+(loginid, email address or TextGrid ID). If mode 'oneinputfield' is set in the \
+configuration there is one input field for either of them, if not, there are \
+three separate input fields."
+text3 = "After pressing the \"verify me\" button the programm is called with \
+'sendlink' status where the programm first checks whether the input values \
+conform to configurable regular expressions \
+(e.g. \".*\\@.*\" for email address), \
+returns respective errors if they do not conform. If they do, the programm \
+looks up the ID in the LDAP server and retrieves an email address from there \
+(even if the ID was the mail address). \
+If the ID was found a separate sessionid (not the ID in the cookie) is created \
+and concatenated to an url that calls status 'printform' and that url is sent \
+to the email address with some configurable text."
+text4 = "If the user clicks on the url in that email, the sessionid in the \
+query is compared with the respective id stored in the session and if they \
+are identical a form to input the password (in two separate input fields) is \
+displayed. After pressing the button \"reset password\" the program is \
+restarted with the status 'modify'."
+text5 = "In this last status again the matching of sessionid is checked, as \
+well as the matching of password and retyped password. Then it is checked how \
+often the session has been used (there is a counter for every access) and \
+whether that number is less than a configurable maximum. The password value is \
+then tested against the configurable regular expression that defines the \
+password policy. If any of these checks fail a respective error message is \
+displayed, otherwise the program looks up the entry and changes the password \
+in the LDAP server."
+text6 = "At any error state, the user either gets the last input screen (e.g. \
+when wrong values have been inputted) or a link to restart the process (e.g. if \
+session is not valid any more). A lot of things are configurable (see the \
+single options below). HTTPS as well as TLS for the LDAP connection can be \
+enforced. All activities can be logged. Configuration concerning input fields \
+(labels, regExp, etc.) happens in a hash at the beginning of the source code. \
+Everything else can be configured in a Apache style configuration file. All \
+passwords needed (for LDAP access and for SMTP auth) are sored in a separate \
+file."
+text7= "If you start the program with status 'adminhelp' \
+(/url/?status=adminhelp) this manpage is displayed in the browser. You can \
+additionally specify one single configuration option to only have the help to \
+that option displayed (e.g. /url/?status=adminhelp&helpfeature=emailconfig). \
+The adminhelp feature can be turned off in the configuration."  
+
+</progdescription>
+ 
+
+<bugs>
+text1 = "Please report bugs to peter.gietz@daasi.de"
+text2 = "some todos are: "
+text3 = "more than one regExp per inputfield"
+text4 = "multilanguage support is already designed but needs gettext translations"
+text5 = "configurable css file does not work properly yet"
+</bugs>
+
+<additions example>
+text1 = "For getting this manpage: "
+text2 = "   pwReset.pl -h"
+text3 = " "
+</additions>
+
+<additions requirements>
+text1 = "Following modules are required: "
+text2 = "* Config::General"
+text5 = "* File::Basename"
+text6 = "* File::Copy"
+text7 = "* File::Flock"
+text8 = "* File::Temp"
+text9 = "* Getopt::Std"
+text10 = "* IO::Prompt"
+text11 = "* Log::Log4perl"
+text12 = "* LWP::Authen::Ntlm"
+text13 = "* MIME::Base64"
+text14 = "* Net::LDAP"
+text15 = "* Net::SMTP"
+text18 = "* Text::Wrap"
+</additions>
+
+<options loglevel>
+        key = "l"
+        must = 0
+        description = "Loglevel for controlling logmessages."
+	description_de = "Loglevel zur Kontrolle des Logging."
+        arg = 1
+        argtype = "skalar"
+	values = "no, all, debug, info, warn, error, fatal" 
+        default = "warn"
+</options>
+
+<options logfile>
+        key = "L"
+        must = 0
+        description = "Name of the logfile with absolute or relative path. "
+	description_de = "Name der Logdatei mit absolutem oder relativem Pfad." 
+        arg = 1
+        argtype = "filename_add_subdir_log"
+        default = "pwReset.log"
+</options>
+
+<options debugmode>
+        key = "d"
+        must = 0
+        description = "Sets debug mode to on."
+        description_de = "Stellt den Debug-Modus an."
+        arg = 0
+</options>
+
+<options verbose>
+        key = "v"
+        must = 0
+        description = "Sets verbose mode which makes the program quite chatty."
+        description_de = "Stellt den Verbose-Modus an, womit das Programm \
+        gespraechiger wird."
+        arg = 0
+</options>
+
+<options language>
+        key = "G"
+        must = 0
+        description = "Sets the language for output like this one"
+        description_de = "Setzt die Sprache fuer Ausgaben wie diese. "
+        arg = 1
+	default = en
+	values = en, de
+</options>
+
+<options passwordfile>
+        key = "p"
+        description = "Name of the password file which contains the secrets \
+		    the programm must know to connect to data bases etc. \
+		    The format for all lines of this file must be: \
+		    <token><blank><password> where <token> has to be the \
+		    option label which defines the database such as e.g. \
+                    \"outputuri\". "
+        description_de = "Name einer Datei, welche die Passworte enthaelt, \
+		    die das Programm wissen muss um Datenbanken zu \
+		    kontaktieren etc. Das Format dieser Datei ist: \
+		    <Token><Leerzeichen><Passwort> wobei <Token> ein \
+		    Optionsname sein muss, welcher die Datenbank \
+		    definiert wie z.B. \"outputuri\". "
+        arg = 1
+	default = "pwReset.secret"
+        argtype = "filename_exist"
+</options>
+
+<options configfile>
+        key = "c"
+        must = 0
+        description = Name of the user config file with absolute or \
+		    relative path."
+        description_de = Name der benutzerdefinierten Konfigurationsdatei \
+		    mit absolutem oder relativem Pfad."
+        arg = 1
+        argtype = "filename_exist_subdir_etc"
+        default = "./etc/pwReset.conf"
+</options>
+
+
+<options printhelp>
+        key = "h"
+        must = 0
+        description = "prints out the manpage"
+        description_de = "Druckt die Manpage aus"
+        arg = 0
+</options>
+
+
+<options helpfeature>
+        key = "H"
+        must = 0
+        description = "prints out description of the feature referenced by \
+	    commandline flag or config file token. "
+        description_de = "Druckt die Beschreibung der Option aus, die \
+	    entweder ueber den Kommandozeilen- oder ueber den \
+	    Konfigurationsdatei-Parameter spezifiziert wird."
+        arg = 1
+</options>
+
+
+<options emailconfig>
+        key = "e"
+        must = 0
+        description = "specifies the SMTP-communication of the program, in a \
+	        string with token-value pairs, format: \
+		\#token1=value1;\#token2=value; etc. \
+		Following tokens are understood: \
+		\#smtprelay sets the mailserver from which the mail should \
+		be sent \
+		\#from sets the from address of the mail to be sent. \
+		\#to sets the mailaddress of the administrator to whom mails \
+		should be sent. More than one address can be separated by \
+		comma. \
+		\#subjectpart sets a prefix that will be included in the \
+		subject line.\n\
+		\#hello sets the smtpclient name.\n\
+		\#smtpuser sets the user name SMTP Auth authentication. \
+ 		In this case the corresponding password has to \
+		be stored in the passwordfile (-p, default is \
+		dbconnector.secret) behind the token smtpauth."
+         description_de = "Spezifiziert das Mail-Interface des Programms \
+	        wodurch in bestimmten Faellen automatische E-Mails an den \
+		Administrator geschickt werden koennen. Das Format besteht \
+		aus mit Semikolon getrennten Schluessel-Wert-Paaren, wobei \
+		der Schluessel mit einem vorgestellten \# gekennzeichnet \
+		wird: \n\
+		\#token1=value1;\#token2=value; etc. \n\
+		Folgende Tokens werden unterstuetzt: \n\
+		\#smtprelay spezifiziert den Mailserver von welchem aus die \
+		Mail geschickt werden soll.\n\
+		\#from spezifiziert die Sender-E-Mail-Adresse.\n\
+		\#to spezifiziert die Ziel-Adresse des Administratoren, an \
+		den die automatischen Mails geschickt werden sollen. \
+		Hierbei koennen mehrere mit Komma separierte Adressen \
+		angegeben werden.\n\
+		\#subjectpart setzt ein Praefix fuer die verschiedenen \
+		Mail-Subjects.\n\
+		\#hello setzt den smtpclient-Namen.\n\
+		\#smtpuser setzt den User-Namen für SMTP \
+		Auth-Authentifizierung. Wenn dieser gesetzt ist, muss \
+ 		das korrespondierende Passwort in der mit \
+		passwordfile spezifizierten Datei (-p, Voreinstellung \
+		ist dbconnector.secret) hinter dem Stichwort smtpauth \
+		eingetragen sein."
+        arg = 1
+	argtype = token_emailinfo
+        default = 0
+</options>
+
+<options cssfile>
+        key = "C"
+        must = 0
+        description = "Name of the CSS file with absolute or \
+		    relative path."
+        description_de = "Name der CSS-Datei \
+		    mit absolutem oder relativem Pfad."
+        arg = 1
+        argtype = "filename_exist_subdir_etc"
+        default = "./etc/pwReset.css"
+</options>
+
+<options sessionpath>
+        key = "s"
+        must = 0
+        description = "Path (relative or absolute) of the directory where to store session information."
+        description_de = "Pfad (relativ oder absolut) zum Verzeichnis, in dem die Session-Informationen gespeichert werden."
+        arg = 1
+        argtype = "filename_dir"
+        default = "./sessions"
+</options>
+
+<options sessionlockpath>
+        key = "S"
+        must = 0
+        description = "Path (relative or absolute) of the directory where to store session lock information."
+        description_de = "Pfad (relativ oder absolut) zum Verzeichnis, in dem die Session-Lock-Informationen gespeichert werden."
+        arg = 1
+        argtype = "filename_dir"
+        default = "./locks"
+</options>
+
+<options sessiontime>
+        key = "T"
+        must = 0
+        description = "Sets the duration of a cookie session. Format: +<number><unit>, where you can specify the following units:  s for seconds, m for minutes, h for hours, d for days, M for months, and y for years"
+        description_de = "definiert die Lebensdauer einer cookie session. Format: +<Nummer><Einheit>, wobei Einheit s für Sekunden, m für Minuten, h für Stunden, d für Tage, M für Monate, und y für Jahre steht. "
+        arg = 1
+	default = "2d"
+</options>
+
+
+<options title>
+        key = "t"
+        must = 1
+        description = "Sets the page title."
+        description_de = "definiert den Seitentitel."
+        arg = 1
+	default = "Password Reset Tool"
+</options>
+
+<options charset>
+        key = "X"
+        must = 1
+        description = "Sets the character set."
+        description_de = "definiert die Zeichensatzkodierung."
+        arg = 1
+	default = "utf-8"
+	values = "utf-8, iso5889" 
+</options>
+
+<options bgcolor>
+        key = "b"
+        must = 0
+        description = "Sets the background color"
+        description_de = "definiert die Hintergrundsfarbe."
+        arg = 1
+	default = "ffffff"
+</options>
+
+<options linkmail>
+        key = "K"
+        must = 0
+        description = "Sets the text for the link mail"
+        description_de = "Definiert die link mail"
+        arg = 1
+	default = "You receive this message, because someone (probably you) requested $ to reset your Password. $ You can do this with following link: %URL%"
+</options>
+
+
+<options meta>
+        key = "M"
+        must = 0
+        description = "Sets the metatags. Format: name1:content1|name2:content2"
+        description_de = "definiert die Meta-Tags. \
+	 Format: name1:content1|name2:content2"
+        arg = 1
+	default = "Robots:noindex,nofollow"
+</options>
+
+<options ldapuri>
+        key = "u"
+        must = 1
+        description = "URI for input of LDAP data. \n\
+		    The format for the LDAP URI is (see RFC 4516): \
+		    ldap://<host>[:<port>]/<basedn>?<attributes>?<scope>?\n\
+		    <filter>?<extension> where <extension> can by now only \
+		    be either bindname=<bindname> for authenticating to the \
+		    server. In this case the corresponding password has to \
+		    be stored in the passwordfile (-p, default is \
+		    dbconnector.secret) behind the token inputuri. \
+		    The second extension supported is \
+		    config=<Slapd-configuration file>, which is only \
+		    needed with inputformat _REPL."
+        description_de = "URI fuer Eingabedaten aus einem LDAP-Server.\n\
+		    Das Format fuer die LDAP-URI (siehe RFC 4516) ist: \
+		    ldap://<host>[:<port>]/<basedn>?<attributes>?<scope>?\n\
+		    <filter>?<extension> wobei als <extension> gegenwaertig \
+		    folgende Erweiterungen unterstuetzt werden:\n\
+		    bindname=<bindname> zur Authentifizierung am Server, \
+		    wobei das korrespondierende Passwort in der mit \
+		    passwordfile spezifizierten Datei (-p, Voreinstellung \
+		    ist dbconnector.secret) hinter dem Stichwort inputuri \
+		    eingetragen sein muss.\n\
+		    config=<Slapd-configuration file>, womit die zu \
+		    verwendende Open-LDAP-Konfigurationsdatei spezifiziert \
+		    wird, was nur im Zusammenhang mit dem inputformat (-I) \
+		    \"_REPL\" benoetigt wird."
+        arg = 1
+        argtype = "uri"
+</options>
+
+<options pwhash>
+        key = "P"
+        must = 1
+        description = "Specifies the password hash algorithm"
+        description_de = "definiert den Passwort-Hash-Algorhitmus"
+        arg = 1
+	default = "SSHA"
+	values = "SSHA, MD5, CRYPT"
+</options>
+
+<options forcehttps>
+        key = "f"
+        must = 0
+        description = "Forces https."
+        description_de = "Erzwingt https."
+        arg = 0
+</options>
+
+<options oneinputfield>
+        key = "o"
+        must = 0
+        description = "Combines all ID-inputfields to one and creates a complex filter"
+        description_de = "vereinigt alle ID-Eingabefelder in eins und baut entsprechende Filter auf"
+        arg = 0
+</options>
+
+<options forcetls>
+        key = "z"
+        must = 0
+        description = "Forces START_TLS in LDAP-connection"
+        description_de = "Erzwingt START_TLS in LDAP-Verbindung"
+        arg = 0
+</options>
+
+<options enableadminhelp>
+        key = "a"
+        must = 0
+        description = "Allows display of adminhelp"
+        description_de = "Erlaubt die Anzeige der Admin-Hilfe"
+        arg = 0
+</options>
diff --git a/info.textgrid.middleware.tgauth.passwordReset/pwReset.pl b/info.textgrid.middleware.tgauth.passwordReset/pwReset.pl
new file mode 100755
index 0000000..0a6c4f3
--- /dev/null
+++ b/info.textgrid.middleware.tgauth.passwordReset/pwReset.pl
@@ -0,0 +1,1062 @@
+#!/usr/bin/perl -w
+
+# pwreset.pl
+
+# author: Peter Gietz
+
+# Version 0.01
+# 10.1.2011
+# copyright DAASI international GmbH 2011
+
+use warnings;
+
+unshift (@INC,"../lib");
+$ENV{PATH}= "/bin:/usr/bin/";
+delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV' };
+umask(077);
+
+
+use vars qw($VERSION $NAME $PATH $PROT);
+
+$VERSION = "0.1";
+$NAME = 'pwReset';
+$PATH =  '/cgi-bin';
+
+$PROT = 'http';
+
+
+use HTTP::Daemon;
+use HTTP::Status;
+
+
+use DAASIlib::CONF qw (is_debug);
+use DAASIlib::LDAP;
+use DAASIlib::LOG;
+use DAASIlib::Convert;
+use DAASIlib::Data;
+use DAASIlib::SMTP;
+#use DAASIlib::XML;
+#use DAASIlib::Objects;
+use DAASIlib::Gettext;
+
+use Crypt::SmbHash qw(lmhash nthash);
+use Digest::MD5 qw(md5 md5_hex md5_base64);
+use Digest::SHA1  qw(sha1 sha1_hex sha1_base64);
+use MIME::Base64;
+use Encode qw(encode);
+use Unicode::Map8;
+use Unicode::String qw(utf16);
+use Apache::Session::File;
+require HTML::Template;
+use URI::Escape;
+
+use utf8;
+
+use strict;
+use vars qw( $count $config );
+use CGI qw/:standard :html3/;
+use CGI::Fast;
+
+local $count =0;
+
+my $conf = new DAASIlib::CONF;
+
+#my $object = new DAASIlib::Objects;
+
+our $data = new DAASIlib::Data;
+our ($progname, $progpath, $etcdir, $sysconfig) = $data->getProgramFiles($0);
+my $gt = $conf->loadConfig($sysconfig, $progpath, $etcdir, 0, $progname);
+$data->init($progname, $conf->{data}{passwordfile});
+
+my $is_verbose = $conf->{data}{verbose};
+
+my $log = new DAASIlib::LOG;
+$log->init($progname, $is_verbose);
+
+#$conf->{data}{logfile} =~/^(.+)$/;
+#my $logfile = $1;
+my $logfile = $conf->{data}{logfile};
+my $logger = $log->initLog4Perl($logfile, 
+                                $conf->{data}{loglevel},
+                                $conf->is_debug() );
+
+$logger->info("$progname started");
+
+if ( $conf->{data}{rewritepath} ) {
+    $PATH = &rewritepath($PATH, $conf->{data}{rewritepath});
+}
+
+
+
+### may be that should become %inputfields ??
+our %inputfields = ( 'mail' => { 
+                         'name' => 'mail',
+			 'type' => 'text',
+			 'len' => 40,
+			 'label' => 'Email address:',
+			 'default' => '',
+			 'regexp' => '.+\@.+\..+',
+			 'ldapattr' => 'mail',
+			 'status' => 'start', 
+			 'priority' => 2, 
+		     },
+		     'login' => { 
+                         'name' => 'login',
+			 'type' => 'text',
+			 'len' => 40,
+			 'label' => 'Login name:',
+			 'default' => '',
+			 'regexp' => '',
+			 'ldapattr' => 'uid',
+			 'status' => 'start', 
+			 'priority' => 1, 
+		     },
+		     'principalname' => {
+                         'name' => 'principalname',
+			 'type' => 'text',
+			 'len' => 40,
+			 'label' => 'TextGrid ID:',
+			 'default' => '',
+			 'regexp' => '.+\@.+',
+			 'rule' => 'must contain an @ character',
+			 'ldapattr' => 'edupersonprincipalname',
+			 'status' => 'end;start', 
+			 'priority' => 3,
+			 'usage' => 'ID',
+		     },	   
+		     'password' => {
+                         'name' => 'password',
+			 'type' => 'password',
+			 'len' => 40,
+			 'label' => 'New password:',
+			 'default' => '',
+			 'regexp' => '.{8,}',
+			 'rule' => 'must be at least 8 chars long',
+			 'ldapattr' => 'userpassword',
+			 'status' => 'printform', 
+			 'priority' => 10, 
+		     },
+		     'retype' => {
+                         'name' => 'retype',
+			 'type' => 'password',
+			 'len' => 40,
+			 'label' => 'Please retype password:',
+			 'default' => '',
+#			 'regexp' => '.{8,}',
+			 'ldapattr' => '',
+			 'status' => 'printform',
+			 'priority' => 11, 
+		     },	   
+   );
+
+our $isdebug = 0;
+our $istest = 0;
+
+while ( my $cgi = new CGI::Fast ) {
+
+    $count++;
+    my $html = &buildResponse ( $cgi, $count );
+    print $html;
+
+}
+
+sub buildResponse {
+    my ( $q, $hitcount ) = @_;
+
+    if ( $q->param('debug') ) {
+	$isdebug=1;
+    }
+
+    if ( $conf->{'data'}{'emailconfig'} ) {
+	foreach my $mailconf ( split /;/,  $conf->{'data'}{'emailconfig'} ) {
+	    my ($key, $value ) = split (/=/, $mailconf, 2);
+	    $key =~ s/^\\//;
+	    $key =~ s/^#//;
+	    $conf->{data}{emailinfo}{$key}=$value;
+	    $logger->debug("found mail configuration: $key=$value");
+	}
+    }
+#    else {
+#	$response .= $q->("Sorry internal Error cannot perform, please send
+#    }
+
+    my $statusmessage = $q->param('status') ? $q->param('status') : 'none';
+
+    $logger->info("pwreset ($VERSION) started, status: $statusmessage");
+    $logger->debug("used sysfile $sysconfig");
+    $logger->debug("used configfile $conf->{data}{configfile}");
+#    $logger->debug("status is: ".$q->param('status')) if $q->param('status') ;
+
+    my %session;
+    my $sessionid = &handlesession($q, \%session, $statusmessage );
+
+#    use Data::Dumper;
+#    my $dumpstr = Dumper(%session);
+
+    foreach my $key ( sort keys %session ) {
+	if ( $key ) {
+	    $logger->debug("session $key: ". $session{$key});
+	}
+    }
+
+    my ($header, $response) = '';
+    
+    $header = &printheader($q);
+    $response .= &debugcgi($q, $hitcount) if $isdebug;
+#    $response .= $q->p("Session: $dumpstr") if $isdebug;
+
+    $response .= $q->h1($conf->{'data'}{'title'});
+
+    my $status = $q->param('status');
+
+    if ( ! $status ) {
+	$logger->debug("buildResponse(): No status thus stating start_process ...");
+	$response .= &startprocess($q);
+#	$response .= $q->h3("No Status, this shouldnd't happen here, please report");
+    }
+    elsif ( $status eq 'testcookie' ) {
+	$response = &testcookie($q);
+    }
+    elsif ( $status eq 'sendlink' ) {
+	$response .= &sendlink($q, \%session);
+#	my ( $resp, $head ) = &sendlink($q);
+#	$response .= $resp;
+#	$header = $head if ($head );
+    }
+    elsif ( $status eq 'printform' ) {
+	$response .= &printform($q, \%session);
+    }
+    elsif ( $status eq 'modify' ) {
+	$response .= &modify($q, \%session);
+    }
+    elsif ( $conf->{data}{enableadminhelp} && $status eq 'adminhelp' ) {
+#	my $lang = $q->param('lang') ? $q->param('lang') : 'en';
+#	$response .= $q->pre(`./$NAME.pl -h -G $lang`);
+	if ( my $feature = $q->param('helpfeature') ) {
+	    $response .= $q->pre(`./$NAME.pl -H $feature`);
+	}
+	else {
+	    $response .= $q->pre(`./$NAME.pl -h`);
+	}
+    }
+    else {
+	$response .= &printerror('status', $q);
+    }
+
+
+    if ( $conf->{data}{forcehttps} && ! $q->https ) {
+	$response = $q->h3("ERROR Programm does not work without HTTPS");
+    } 
+
+    $response .= &printtail( $q);
+
+    $logger->info("$progname ended");
+
+
+    $response = "$header$response";
+
+    return $response;
+
+}
+
+sub handlesession {
+    my ( $q, $rh_session, $status ) = @_;
+
+#    my %session;
+#    my $exist = '';
+    
+    my $sid =  $q->cookie ( -name => $NAME );
+
+    if ( $sid ) {
+
+	my $sessionfile = $conf->{'data'}{ 'sessionpath' }."/$sid";
+	if ( -e $sessionfile  ) {
+#	    $exist = $sid;
+	    $logger->debug( "Session-Management: Reading session $sid");
+	    tie %{$rh_session}, "Apache::Session::File", $sid, 
+	    { Directory => $conf->{'data'}{ 'sessionpath' }, 
+	      LockDirectory => $conf->{'data'}{ 'sessionlockpath'} 
+	    };
+	}
+	else {
+	    $logger->debug( "Session-Management: creating new session $sid");
+
+	    tie %{$rh_session}, "Apache::Session::File", undef, 
+	    { Directory => $conf->{'data'}{ 'sessionpath' }, 
+	      LockDirectory => $conf->{'data'}{ 'sessionlockpath'} 
+	    };
+	    $sid = $rh_session->{_session_id};
+	    $rh_session->{'counter'}=0;
+	    &setcookie( $q, $sid) ;
+	}
+    }
+    else {
+	tie %{$rh_session}, "Apache::Session::File", undef, 
+	{ Directory => $conf->{'data'}{ 'sessionpath' }, 
+	  LockDirectory => $conf->{'data'}{ 'sessionlockpath'} 
+	};
+	$sid = $rh_session->{_session_id};
+	$rh_session->{'counter'}=0;
+	&setcookie( $q, $sid) ;
+    }
+
+    if ( $rh_session->{'status'} ) {
+	$rh_session->{'laststatus'} = $rh_session->{'status'};
+    }
+    $rh_session->{'status'} = $status;
+    $rh_session->{'counter'} += 1;
+
+
+    return $sid;
+}
+ 
+
+
+sub startprocess {
+    my ( $q ) = @_;
+
+    my $response = '';
+    
+    my $status = 'sendlink';
+
+    my %params;
+    $params{status}=$status;
+    my $url = &createurl($q, \%params);
+
+    $q->param('status', $status);
+
+    $response .= $q->h2("Identify yourself");
+    $response .= $q->p("my url: $url") if $isdebug;
+
+    $response .= $q->start_form( -method => 'post',
+				 -action => $url,
+	);
+
+
+    $response .= &printfields ($q, 'start', $conf->{'data'}{'oneinputfield'});
+    $response .= &printhiddens($q, $status);
+
+    $response .= $q->submit(-name =>'button_name',
+			    -value =>'verify me',
+	                   );
+
+    $response .= $q->end_form;
+
+    return $response;
+}
+
+sub createid {
+
+    my $id = "xaOUd".rand(100000)."ff1A.846";
+    
+
+    return $id;
+}
+
+sub setcookie {
+    my ( $q, $sid ) = @_;
+    my $status = $q->param('status') ? $q->param('status'): 'none' ;
+    $logger->debug("setcookie(): Status is: $status, SID is: $sid");
+
+    my %params;
+    if ( $status ne 'testcookie' && $status ne 'adminhelp' ) {
+#    if ( $status ne 'testcookie' ) {
+#	my $id = $sid;
+	$params{'status'}='testcookie';
+	my $nexturl = &createurl($q, \%params);
+#       my $server = $q->server_name;
+	#   my $id = &createid();
+	my $cookietime = ($status eq 'modify') ? 'now' : &getcookietime();
+
+	my $cookie = $q->cookie(-name => $NAME,
+				-value   => $sid,
+				-expires => $cookietime,
+				-path    => $PATH,
+#                             -domain  => 'XXX',
+#                             -secure  => 1,
+	    );
+	
+	$logger->debug(" setcookie(): sending |$cookie| via redirect to testcookie");
+	print $q->redirect ( -url => $nexturl,
+			     -cookie => $cookie );
+	exit();
+    }
+}
+
+sub createurl {
+    my ( $q, $rh_params ) = @_;
+    
+    my $server = $q->server_name;
+    my $url = $q->url();
+
+    if ( $conf->{data}{rewritepath} ) {
+	$url = &rewritepath($url, $conf->{data}{rewritepath});
+    }
+
+    my $token = '?';
+    if ( $rh_params ) {
+	foreach my $key ( keys %{$rh_params} ) {
+	    $url .= $token;
+	    $url .= $key.'='.$rh_params->{$key};
+	    $token = '&';
+	}
+    }
+    $url .= "${token}debug=".$q->param('debug') if $q->param('debug') ;
+
+#    $status ? 
+#	"$PROT://$server$PATH/$NAME.pl?status=$status" :
+#	"$PROT://$server$PATH/$NAME.pl";
+    
+    $logger->debug("createurl(): created url $url");
+    return $url;
+}
+
+sub testcookie {
+    my ( $q ) = @_;
+    my $response='';
+
+    my $cookie = $q->cookie ( -name => $NAME );
+    my $nexturl = &createurl( $q, undef);
+    $logger->debug("testcookie(): Cookie is: $cookie");
+
+    if ( defined $cookie ) {
+#	$response .= $q->h2("TESTCOOKIE: SUCCESS");
+	$logger->debug("testcookie(): Found cookie, will proceed");
+	$q->param('status', 'sendlink');
+	$response .= $q->h1($conf->{'data'}{'title'});
+	$response .= &startprocess($q);
+    }
+    else {
+	$logger->warn("testcookie(): Cookies seem to be disabled");
+
+	$response .= $q->h2( "Cookies Disabled!" );
+	$response .= $q->h3( "Your browser is not accepting cookies");
+	$response  .= $q->p( "Please enable cookies in your browser preferences and ".
+		   $q->a( { -href => $nexturl }, "return to start").
+		   "."
+	    );
+    }
+   
+    return $response;
+}
+
+sub sendlink {
+    my ( $q, $rh_session ) = @_;
+    my ($header, $response) = '';
+
+    $response .= $q->h2("Verification and sending email");
+
+    if ( my $paramerrors = &getparamerrors ( $q ) ) {
+#    if ( $paramerrors ) {
+	$response .= $paramerrors;
+	$response .= $q->p("Please try again");
+	$response .=  &startprocess($q);
+	return $response;
+    }
+
+    my $searchquery = &getsearchquery($q, 'start');
+    $logger->debug("sendlinkl(): searchquery is $searchquery");
+
+    my $filter = &createfilter( $q, $searchquery, 'start');
+    my ( $searchresponse, $mail, $entry ) =  &searchentry($q, $rh_session, $filter);
+    $response .= $q->b($searchresponse) if $searchresponse  ;
+    my $user = " (".$q->param($searchquery).")";
+
+    if ( ! $mail ) {					     
+	$response .= &startprocess($q);
+    }
+    else {
+	$response .=$q->p("Your TextGrid account $user exists.");
+	$response .= $q->p("\nsmtpserver: ".$conf->{data}{emailinfo}{smtprelay}) if $isdebug;
+	$response .= &sendlinkmail($q, $mail, $rh_session);
+    }
+
+    return $response;
+}
+
+sub getsearchquery {
+    my ( $q, $status ) = @_;
+    my $searchquery = '';
+
+    if ( $q->param('search') ) {
+	$searchquery = 'search';
+    }
+    else {
+	foreach my $f ( sort prioritysort keys %inputfields ) {
+	    if ( grep ( /$status/, split(/;/, $inputfields{$f}{status}) ) ) { 
+		if ( $q->param($inputfields{$f}{name}) ) {
+		    $searchquery = $inputfields{$f}{name};
+		    last;
+		}
+	    }
+	}
+    }
+    
+    return $searchquery;
+}
+
+
+sub sendlinkmail {
+    my ( $q, $mail, $rh_session ) = @_;
+    my $response = '';
+
+    my $status = 'printform';
+    my $smtp = new DAASIlib::SMTP;
+
+    
+    $smtp->set_server($conf->{data}{emailinfo}{smtprelay});
+    my $subject = $conf->{data}{emailinfo}{subjectpart};
+    $subject .= " How to reset your TextGrid password"; 
+    my $body = $conf->{data}{linkmail};
+    my ($cc, $bcc, $pw) = '';
+    $body =~ s/\$/\n/g;
+
+    my $secret = &createid();
+
+#    my $url = $q->url();
+#    $url .= "?status=printform&sessionid=$secret";
+#    $url .= "&debug=".$q->param('debug') if $q->param('debug') ;
+
+    my %params;
+    $params{status}=$status;
+    $params{sessionid}=$secret;
+    my $url = &createurl($q, \%params);
+
+    $rh_session->{'secret'} = $secret;
+
+    $body =~ s/%URL%/$url/;
+
+    my $result = $smtp->send_mail($conf->{data}{emailinfo}{from},
+		    $subject,$body,$mail,$cc,$bcc,
+	            $conf->{data}{emailinfo}{hello},
+	            $conf->{data}{emailinfo}{smtpuser},
+	) if ! $istest;
+
+    $response .= $q->p("An email has been sent to $mail.");
+
+    
+
+    return $response;
+
+}
+
+
+sub createfilter {
+    my ( $q, $searchquery, $status ) = @_;
+
+    my ( $searchattr, $filter ) = '';
+
+    if ( $searchquery eq 'search' ) {
+	$filter = '( | ';
+	foreach my $f ( sort prioritysort keys %inputfields ) {
+	    if ( grep ( /$status/, split(/;/, $inputfields{$f}{status}) ) ) { 
+		$searchattr = $inputfields{$f}->{'ldapattr'};
+		if ( $searchattr ) {
+		    $filter .= "($searchattr=".$q->param($searchquery).")";
+		}
+	    }
+	}
+	$filter .= ')';
+    }
+    else {
+	$searchattr = $inputfields{$searchquery}{'ldapattr'};
+	$filter = "($searchattr=".$q->param($searchquery).")";
+    }
+
+    $logger->debug("createfilter(): created filter $filter");
+    return $filter;
+}
+
+sub searchentry {
+    my ( $q, $rh_session, $filter, $ldap ) = @_;
+    my $response = '';
+
+    my $searchattr;
+#    my $filter;
+    my $mail;
+    my $entry;
+    my $shouldclose = 0;
+
+    my @attrs = &getattrs('start');
+
+
+    $response .= $q->p("searching with Filter $filter") if $isdebug; 
+    
+
+    my $libldap = new DAASIlib::LDAP;
+    my $rh_ldap = $libldap->defineServerFromURI($conf->{data}{ldapuri}, 
+						'ldapuri', 0);
+    $rh_ldap->{is_tls} = 1 if $conf->{data}{forcetls};
+
+#    $rh_ldap->{scope}  = 'sub'; 
+
+    $rh_ldap->{attribs}  = \@attrs; 
+    $rh_ldap->{filter}  = $filter; 
+
+    if ( ! $ldap ) {
+#    my $ldap = $libldap->connectServer($rh_ldap, 1);
+	$ldap = $libldap->connectServer($rh_ldap);
+	if ( ! $ldap ) {
+	    $response .= $q->p("could not connect to LDAP-Server");
+	    return $response;
+	}
+	$shouldclose = 1;
+    }
+
+    my $mesg = $libldap->doSearch($ldap, $rh_ldap);
+    if ($mesg->count()) {
+	if ( $mesg->count() > 1 ) {
+	    $response .= $q->p("Error: found more than one entry!!!");
+	    $logger->error("Error: found more than one entry!!!");
+	}
+
+	$entry = $mesg->pop_entry();
+	my $entrydn= $entry->dn();
+	$logger->debug("found entry $entrydn");	
+        $mail = $entry->get_value('mail');
+	foreach my $attr ( @attrs ) {
+	    $rh_session->{$attr} = $entry->get_value($attr);
+	}
+	if ( ! $mail ) {
+	    $response .= $q->p("Error: could not find an email to send message to");
+	    $logger->error("Error: could not find an email to send message to");
+	}
+    }
+    else {
+	$logger->debug("found no entry with filter $filter");	
+	$response .= $q->p("Error: there is no user with $filter");
+	$logger->error("Error: there is no user with $filter");
+    }
+
+    if ( $shouldclose ) {
+	$ldap->unbind;
+    }
+
+    return $response, $mail, $entry;
+}
+
+sub printform {
+    my ( $q, $rh_session ) = @_;
+
+    $logger->debug("printform(): started");
+    my $status = '';
+    my $response = '';
+    $response .= $q->h2("Input of new password");
+    my $cookie = $q->cookie(-name => 'pwReset');
+
+#   use Data::Dumper;
+#    $response .= $q->p(Dumper($cookie));
+    my $secret = $rh_session->{'secret'};
+
+    if ( $q->param('sessionid') eq $secret ) {
+
+	$response .= $q->h3("Everything went fine, you can now reset your Password");
+	$status = 'modify';
+	my %params;
+	$params{'status'}=$status;
+	my $url = &createurl($q, \%params);
+
+	$response .= $q->start_form( -method => 'post',
+				 -action => $url,
+	    );
+	$response .= &printfields ($q, 'printform');
+	$logger->debug("printform(): status: $status");
+	$response .= &printhiddens($q, $status);
+
+	$logger->debug("printform(): fine so I set status to $status");
+	$response .= $q->submit(-name =>'button_name',
+				-value =>'reset password',
+	    );
+	$response .= $q->end_form;
+
+    }
+    else {
+	my $cookietimestring  = &getcookietimestring();
+	$response .= $q->h3("There has been an Error").
+	    $q->p("This can be out of one of the following reasons:"). 
+	    $q->ul( $q->li({-type=>'disc'},
+			   [
+			    "Your browser didn't allow to set a cookie",
+			    "You used a different browser, when requesting the reset",
+			    "The request is too old (older than $cookietimestring)",
+			    "Any other unforseen error",
+			   ]));
+    }
+
+    return $response;
+}
+
+
+sub modify {
+    my ( $q, $rh_session ) = @_;
+    
+    my $response = '';
+    my $cookie = $q->cookie(-name => 'pwReset');
+    my $secret = $rh_session->{'secret'};
+    my $user = $rh_session->{'edupersonprincipalname'};
+    my $maxcount = 40;
+
+    my $libldap = new DAASIlib::LDAP;
+    my $rh_ldap = $libldap->defineServerFromURI($conf->{data}{ldapuri}, 
+						'ldapuri', 0);
+    $rh_ldap->{is_tls} = 1 if $conf->{data}{forcetls};
+    my $ldap = $libldap->connectServer($rh_ldap);
+#    my $maxcount = 4;
+
+    $response .= $q->h2("Modifying Password");
+    
+    if ( $q->param('sessionid') eq $secret ) {
+	if ( $q->param('password') eq $q->param('retype') ) {
+	    if ( $rh_session->{'counter'} > $maxcount ) {
+		$response .= $q->p("ERROR: Session is not valid any more, because it was called too often. You have to begin the process again");
+		tied(%{$rh_session})->delete;
+		my $url = &createurl($q, undef);
+		$response .= $q->a( { -href => $url }, "return to start");
+#		$response .= &startprocess($q);		
+	    }
+	    elsif (  my $paramerrors = &getparamerrors ( $q ) ) {
+		$response .= $paramerrors;
+		$response .= $q->p("Please try again");
+		$response .= &printform($q, $rh_session);
+	    }
+	    else {
+		my $idattr = $inputfields{&getidfield()}{'ldapattr'};
+		my $user = $rh_session->{$idattr};
+		my $filter = "($idattr=$user)";
+		my ( $searchresponse, $mail, $entry ) =  &searchentry($q, $rh_session, $filter);
+		my $entrydn = $entry->dn();
+		$response .= $q->p("Password for user $user will be reset");
+#		$response .= "entry: $entrydn";
+		my $plain = $q->param('password');
+		my $digest =  $conf->{'data'}{'pwhash'};
+		my $encodedPassword = `/usr/sbin/slappasswd -h {$digest} -s \'$plain\'`;
+
+		$logger->debug("changing Password of entry $entrydn at ". 
+			       $conf->{data}{ldapuri});
+		$entry->replace ( 
+		    $inputfields{'password'}{'ldapattr'} => $encodedPassword
+		    );
+		my $res = $entry->update($ldap); 
+
+## The following produces crypt passwords, that didn't work
+#		use Net::LDAP::Extension::SetPassword;
+#		my $res = $ldap->set_password(
+#		    newpasswd => $q->param('password'),
+#		    user      => $entrydn
+#		    );
+		$logger->debug("Result of password change: ".$res->error());
+		$response .= $q->p("result of update: ".$res->error());
+		$ldap->unbind;		
+	    }
+	}
+	else {
+	    $response .= $q->p("ERROR: the password and the retyped password did not match, please try again");
+	    $response .= &printform($q, $rh_session);
+	}
+    }
+    else {
+	$response .= $q->p("ERROR: sessionid: $secret not returned in query: ".$q->param('sessionid') );
+    }
+    
+    return $response;
+}
+
+sub getidfield {
+    my $idfield='';
+    foreach my $key ( keys %inputfields ) {
+	if ( $inputfields{$key}{ 'usage'} eq 'ID') {
+	    $idfield = $key;
+	}
+    }
+    $idfield = $idfield ? $idfield : 'edupersonprincipalname';
+    return $idfield;
+}
+
+sub getcookietime {
+    my $string='';
+
+    if ( $conf->{'data'}{'sessiontime'} =~/(\d+)([smhdMy])/ ) {
+	$string = '+'.$conf->{'data'}{'sessiontime'};
+    }
+    else {
+	$logger->error("ERROR: wrong Format in configuration of sessiontime");
+    }
+
+    return $string;
+}	     
+
+
+sub getcookietimestring {
+    my $string='';
+
+    my %units = (
+	's' => 'seconds',
+	'm' => 'minutes',
+	'h' => 'hours',
+	'd' => 'days',
+	'M' => 'months',
+	'y' => 'years',
+	);
+
+    my $num;
+    my $unitstring;
+
+    if ( $conf->{'data'}{'sessiontime'} =~/(\d+)([smhdMy])/ ) {
+	$num = $1;
+        $unitstring = $units{$2};
+	$string = "$num $unitstring";
+    }
+
+    return $string;
+}	     
+
+
+sub rewritepath { 
+    my ($path,$rules) = @_;
+    
+    foreach my $rule ( split / ?; ?/, $rules ) {
+	my ($from, $to ) = split / ?=> ?/, $rule;
+	$path =~s/$from/$to/;
+    }
+    return $path;
+}
+
+sub printhiddens {
+    my ( $q, $state ) = @_;
+    my $fields='';
+
+
+    $logger->debug("printhiddens(): got status:        $state");
+    $state = $state ? $state : $q->param('status');
+    $logger->debug("printhiddens(): changed status to: $state");
+###    $fields .= $q->hidden( 'status', "$state");
+#### There seems to be a bug in the CGI-library, since the above didn't work ( 
+    $fields .= "<input type=\"hidden\" name=\"status\" value=\"$state\"/>";
+
+    $fields .= $q->hidden( 'sessionid', $q->param('sessionid') ) 
+	if $q->param('sessionid') ;
+
+#    $fields .= $q->hidden( -name => 'status', -default => "XXX${status}YYY");
+#    $fields .= $q->hidden( -name => 'sxxxx', -default => "XXX${status}YYY");
+#    $fields .= $q->hidden( -name => 'sessionid', -default => $q->param('sessionid') ) 
+#	if $q->param('sessionid') ;
+
+    if ( $q->param('debug') ) {
+	$fields .= $q->hidden( -name => 'debug', -default => $q->param('debug'));
+	$fields .= $q->p("debug is on");
+    }
+    $logger->debug("printhiddens(): returning fields: $fields");
+    return $fields;
+    
+}
+
+sub prioritysort {
+    $inputfields{$a}->{'priority'}<=>$inputfields{$b}->{'priority'}
+}
+
+sub getattrs {
+    my ($status) = @_;
+    my @attrs=();
+    $logger->debug("getattrs(): got status $status");
+
+    foreach my $f ( sort prioritysort keys %inputfields ) {
+	if ( grep ( /$status/, split(/;/, $inputfields{$f}{status}) ) ) { 
+	    push @attrs, $inputfields{$f}{ldapattr};
+	    $logger->debug("getattrs(): found attribute: ".$inputfields{$f}{ldapattr});
+	}
+    }
+    return @attrs;
+}
+
+sub printfields {
+    my ($q, $status, $isonefield) = @_;
+    my $fields='';
+    my $labels = 'Please input either ';
+#Please input either your Login Name, your E-Mail address or your TextGrid ID. Your password can only be changed for @textgrid.de TextGrid IDs
+    foreach my $f ( 
+	sort { $inputfields{$a}->{'priority'}<=>$inputfields{$b}->{'priority'} }
+	keys %inputfields ) {
+
+	if ( grep ( /$status/, split(/;/, $inputfields{$f}{status}) ) ) { 
+	    if  ( $inputfields{$f}{type} eq 'text' ) {
+		my $label =  $inputfields{$f}->{'label'};
+		$label =~ s/(.*):\s?/$1/;
+		$labels .= "your $label or ";
+		$fields .= &printtextfield($q,  $inputfields{$f});
+	    }
+	    elsif (  $inputfields{$f}->{type} eq 'password' ) {
+		$fields .= &printpasswordfield($q, $inputfields{$f});
+	    }
+	    else {
+		$fields .= &printerror('input type', $q); 
+	    }
+	    $fields .= $q->br;
+	}
+    }
+
+    if ( $isonefield ) {
+	$labels =~ s/ or $//;
+        $labels .= "<br>\n (Your password can only be changed for \@textgrid.de TextGrid IDs)";
+	$fields = $labels.": ".$q->br.$q->br;
+	$fields .= $q->textfield(
+	    -name => 'search',
+	    -value => '',
+	    -size =>40,
+	    -maxlen => 40,
+	);
+    }
+   
+    return $fields;
+}
+
+sub printtextfield {
+    my ($q,$f, $label) = @_;
+    
+    my $field = '';
+    $label = $label ? $label : $f->{'label'};
+    $field .= $label.$q->br;
+    $field .= $q->textfield(
+	-name => $f->{'name'},
+	-value => $f->{'default'},
+	-size => $f->{'len'},
+	-maxlen => $f->{'len'},
+	);
+
+    return $field;
+}
+
+sub printpasswordfield {
+    my ($q,$f) = @_;
+    
+    my $field = '';
+    $field .= $f->{'label'}.$q->br;
+    $field .= $q->password_field(
+	-name => $f->{'name'},
+	-value => $f->{'default'},
+	-size => $f->{'len'},
+	-maxlen => $f->{'len'},
+	);
+
+    return $field;
+}
+
+
+
+sub printtail {
+    my ( $q) = @_;
+
+    my $tail = $q->end_html();
+
+    return $tail;
+}
+
+
+sub printheader {
+    my ( $q ) = @_;
+
+    my $header = $q->header(
+	                -type   => 'text/html',
+                        -charset=> $conf->{'data'}{'charset'},
+        #               -pragma => 'no-cache', # for debugging only
+        #               -expires=> 'now', # for debugging only
+                        -expires=> '+3m', # should be used in production
+#	                -cookie => $cookie,
+                        );
+
+#    if ( $cookie ) {
+#	$logger->debug("Setting Cookie");
+#    }
+
+    my $color = $conf->{'data'}{'bgcolor'};
+
+#    if ( $color !~ /#/ ) {
+#	$color = '#'.$color;
+#    }
+
+    my %metas;
+
+    foreach my $metadef ( split /\|/, $conf->{'data'}{'meta'} ) {
+	my ($name,$content) = split /:/, $metadef, 2;
+	$metas{$name}=$content;
+    }
+    $header .= $q->start_html(
+	                -title => $conf->{'data'}{'title'},
+	                -bgcolor => $color,
+	                -meta => \%metas,
+#	                -style => { -src => [ $conf->{'data'}{'cssfile'} ], 
+#                                    -media => 'all'},
+	);
+
+ 
+    return $header;
+}
+
+
+sub printerror {
+    my ( $err, $q) = @_;
+
+    my $error = $q->p("Error: wrong $err");
+
+    return $error;
+}
+
+sub getparamerrors {
+    my ( $q ) = @_;
+
+    my $errors = '';
+    my @names = $q->param();
+
+    foreach (@names) {
+	my $value = $q->param($_);
+	my $regexp = $inputfields{$_}{'regexp'};
+	my $rule = $inputfields{$_}{'rule'};
+	$rule = $rule ? 
+	    "rule \"$rule\"" :
+	    "Regular Expression /$regexp/";
+	my $display;
+
+	if (  $inputfields{$_}{'type'} eq 'password' ) {
+	    $display = "[not displayed]";
+	}
+	else {
+	    $display = $value;
+	}
+	if ( $value && $regexp && $value !~ /$regexp/ ) {
+	    $errors .= $q->p("Error in inputfield $_: value \"$display\" does not conform to $rule");
+	}
+    }    
+
+    return $errors;
+}
+
+sub debugcgi {
+    my ( $q, $hitcount ) = @_;
+
+    my $response = '';
+    $response .= $q->h3("Debuginfo");
+    $response .= $q->p("This is hit number <b>$hitcount</b>");
+
+    my @keywords = $q->keywords();
+    my @names = $q->param();
+
+    my @values;
+
+    foreach (@names) {
+	push @values,"$_: ".$q->param($_);
+    }    
+    $response .= $q->ul( $q->li({-type=>'disc'},["Q keywords: @keywords", "Q param: @names"])); 
+    if ( @values ) {
+        $response .= $q->p("Query has following param / value pairs:"); 
+	$response .= $q->ul( $q->li({-type=>'disc'}, @values)); 
+    }
+
+    $response .= $q->p("remote host: ".$q->remote_host());
+    $response .= $q->p("remote addr: ".$q->remote_addr());
+    $response .= $q->p("user agent: ".$q->user_agent());
+
+    $response .= $conf->getConf("current configuration:");
+
+
+    return $response;
+
+}
diff --git a/info.textgrid.middleware.tgauth.passwordReset/svn-commit.tmp b/info.textgrid.middleware.tgauth.passwordReset/svn-commit.tmp
new file mode 100644
index 0000000..790bb93
--- /dev/null
+++ b/info.textgrid.middleware.tgauth.passwordReset/svn-commit.tmp
@@ -0,0 +1,5 @@
+Checcked in Version with proxy path rewrite feature
+
+--This line, and those below, will be ignored--
+
+A    etc
-- 
GitLab