Archive for the ‘Programmieren’ Category

Briefvorlage mit LaTeX

Ich bin vor kurzem umgezogen und bin inzwischen Besitzer eines Festnetztelefon. Aus diesem Grund wollte ich in meiner \LaTeX-Vorlage für meine Briefe beide Nummern stehen haben. Die KOMA-Skript Pakte können von Haus aus, nur eine Telefonnummer, deswegen habe ich meine Vorlage, welche ich von meet-unix habe, wie folgt angepasst.

\ProvidesFile{letter_options.lco}[letter-class-option file]
 
% symbols: (cell)phone, email
\RequirePackage{marvosym} 
% for gray color in header
\RequirePackage{color}
\RequirePackage[utf8]{inputenc}
 
\KOMAoptions{
foldmarks=true,
foldmarks=BlmTP,
%fromurl=true,
fromemail=true,
fromphone=true,
fromalign=right,
fromrule=aftername,
fromemail=true,
footsepline=off
}
 
% define gray for header
\definecolor{firstnamecolor}{rgb}{0.65,0.65,0.65}
\definecolor{familynamecolor}{rgb}{0.45,0.45,0.45}
 
\setkomavar{fromname}{\color{firstnamecolor}Michael\color{familynamecolor}Rennecke}
\setkomafont{fromname}{\fontsize{38}{40}\sffamily\mdseries\upshape}
 
\setkomafont{fromrule}{\color{firstnamecolor}}
\@setplength{fromrulethickness}{0.25ex}
 
\setkomafont{addressee}{\small}
\setkomavar{fromaddress}{Solarisgasse 2\\12345 Tuxhausen}
 
\newkomavar[\Mobilefone]{frommobilephone} 
\setkomavar{frommobilephone}{(01\,60)~1\,23\,45\,67}
\setkomavar{fromphone}[\Telefon]{(03\,45)~12\,34\,56\,78}
 
\setkomavar{fromemail}[\Letter]{michael\_rennecke@gmx.net}
%\setkomavar{fromurl}[]{http://0rpheus.net}
 
\firsthead{
  \noindent
  \parbox[b]{\useplength{firstheadwidth}}{
    \noindent%
    \raggedleft%
    {\usekomafont{fromname}\usekomavar{fromname}}\\
    \rule{\useplength{firstheadwidth}}{1pt}\\
    \usekomavar{fromaddress}\\
    \Telefon\enskip\usekomavar{fromphone}\\
    \Mobilefone\enskip\usekomavar{frommobilephone}\\
    \Letter\enskip\usekomavar{fromemail}
  }
}
 
\setkomafont{fromaddress}{\small\rmfamily\mdseries\slshape}
\setkomavar{backaddress}{Michael Rennecke, Große Schlossgasse 2, 06108 Halle (Saale)}
 
\setkomavar{signature}{Michael Rennecke}
% signature same indention level as rest
\renewcommand*{\raggedsignature}{\raggedright}
% space for signature
\@setplength{sigbeforevskip}{1.7cm}
 
\endinput

So sieht nun ein Beipieldokument aus:

\documentclass[letter_options,parskip=half+,version=last,fontsize=11pt,DIV=11,BCOR=10mm, DIN]{scrlttr2}
 
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[english,ngerman]{babel}
\usepackage{amssymb}
\usepackage{lmodern}
 
% overall sans serif font
\renewcommand{\familydefault}{\sfdefault}
 
\setkomavar{subject}{Was machst Du}
\setkomavar{place}{Halle (Saale)}
 
\begin{document}
\begin{letter}{Karl Mustermann\\ Straße 4\\ 06019 Halle (Saale)}
 
 
\opening{Sehr geehrte Damen und Herren,}
  blabla
 
  \closing{Mit freundlichem Gruß}
\end{letter}
 
\end{document}

Ich hoffe ich konnte allen helfen, die ein ähnliches Problem haben. Ich bin für Anmerkungen dankbar, die meine Vorlage noch verbessern ;-) Wie das aussieht kann man hier sehen

verschlüsselte Volumes bequem mounten

Ich habe mein home verschlüsselt. Dieses wird automatisch, beim anmelden gemountet. Da ich in mein home noch ein paar andere verschlüsselte Dateisysteme einhänge funktionieren die Standard-Mittel, wie /etc/crypttab nicht. Dabei ergibt sich das folgende Problem: Die Volumes werden beim booten eingehangen und zu diesen Zeitpunkt existiert mein home noch nicht.

Da ich faul bin möchte ich auch möglichst wenig Passwörter eingeben, weiterhin soll meine Freundin auch den Rechner anmachen können und nicht an meinen Passwort scheitern. Deswegen wird nur mein home via Passwort entschlüsselt, für die anderen Dateisysteme kommen key-files zum Einsatz. Diese liegen in meinen verschlüsselten home.

Da ich mir selbst nicht vertraue, möchte ich den sudo-Mechanismus oder suid-Bits nicht benutzten. Deswegen habe ich mir die beiden Skripte cryptdisks_start und cryptdisks_stop genauer angesehen. In einen ersten Schritt habe ich mir eine /etc/user_crypttab erzeugt.

root@walhalla ~ # cat /etc/user_crypttab
# definition             volume                        key                                   options      mountpoint                mountoptions
data--group-video_crypt  /dev/mapper/data--group-video /home/rennecke/key-files/video-key    luks         /home/rennecke/Videos     noatime

Die ersten vier Parameter entsprechen denen, der crypttab, mountpoint und mountoptions sind entsprechen den gleichnamigen Optionen von mount.

Mein user_cryptdisks_start-Skript sieht wie folgt aus:

#!/bin/sh
 
# user_cryptdisks_start - wrapper around cryptsetup which parses
# /etc/user_crypttab, just like mount parses /etc/fstab.
 
# Initial code stolen from cryptdisks_start by Jon Dowland <jon@alcopop.org>
# Copyright (C) 2011 by Michael Rennecke <michael_rennecke@gmx.net>
# License: GNU General Public License, v2 or any later
# (http://www.gnu.org/copyleft/gpl.html)
 
CRYPTTAB="/etc/user_crypttab"
 
set -e
 
if [ $# -lt 1 ]; then
	echo "usage: $0 <name>" >&2
	echo >&2
	echo "reads $CRYPTTAB and starts the mapping corresponding to <name>" >&2
	exit 1
fi
 
. /lib/cryptsetup/cryptdisks.functions
 
INITSTATE="manual"
DEFAULT_LOUD="yes"
 
if [ -x "/usr/bin/id" ] && [ "$(/usr/bin/id -u)"  != "0" ]; then
	log_warning_msg "$0 needs root privileges"
	exit 1
fi
 
log_action_begin_msg "Starting crypto disk"
mount_fs
 
 
count=0
tablen="$(egrep -vc "^[[:space:]]*(#|$)" "$CRYPTTAB")"
egrep -v "^[[:space:]]*(#|$)" "$CRYPTTAB" | while read dst src key opts mnt mopts; do
	count=$(( $count + 1 ))
	echo ""
	if [ "$1" = "$dst" ]; then
		ret=0
		handle_crypttab_line_start "$dst" "$src" "$key" "$opts" <&3 || ret=$?
		echo ""
		fsck -pv /dev/mapper/$dst
		echo ""
		mount -o $mopts /dev/mapper/$dst $mnt
	elif [ $count -ge $tablen ]; then
		ret=1
		device_msg "$1" "failed, not found in user_crypttab"
	else
		continue
	fi
	umount_fs
	log_action_end_msg $ret
	exit $ret
done 3<&1

Zum Schluss noch mein user_cryptdisks_stop-Skript:

#!/bin/sh
 
# user_cryptdisks_stop - wrapper around cryptsetup which parses
# /etc/user_crypttab, just like mount parses /etc/fstab.
 
# Initial code stolen from cryptdisks_stop by Jonas Meurer <jonas@freesources.org>
# Copyright (C) 2011 by Michael Rennecke <michael_rennecke@gmx.net>
# License: GNU General Public License, v2 or any later
# (http://www.gnu.org/copyleft/gpl.html)
 
CRYPTTAB=/etc/user_crypttab
 
set -e
 
if [ $# -lt 1 ]; then
	echo "usage: $0 <name>" >&2
	echo >&2
	echo "reads $CRYPTTAB and stops the mapping corresponding to <name>" >&2
	exit 1
fi
 
. /lib/cryptsetup/cryptdisks.functions
 
INITSTATE="manual"
DEFAULT_LOUD="yes"
 
if [ -x "/usr/bin/id" ] && [ "$(/usr/bin/id -u)"  != "0" ]; then
	log_warning_msg "$0 needs root privileges"
	exit 1
fi
 
log_action_begin_msg "Stopping crypto disk"
echo ""
 
count=0
tablen="$(egrep -vc "^[[:space:]]*(#|$)" "$CRYPTTAB")"
egrep -v "^[[:space:]]*(#|$)" "$CRYPTTAB" | while read dst src key opts mnt mopts; do
	count=$(( $count + 1 ))
	if [ "$1" = "$dst" ]; then
		umount $mnt
 
		ret=0
		handle_crypttab_line_stop "$dst" "$src" "$key" "$opts" <&3 || ret=$?
	elif [ $count -ge $tablen ]; then
		ret=1
		device_msg "$1" "failed, not found in user_crypttab"
	else
		continue
	fi
	log_action_end_msg $ret
	exit $ret
done 3<&

Die beiden Skripte kann nun root ausführen, um Dateisysteme einzuhängen. Bei jeden einhängen wird geschaut, ob ein fsck nötig ist. Mein Dank gilt meet-unix, er hat stand mit mit Rat zu Seite, da ich noch etwas Solaris-geschädigt bin. Anmerkungen, bitte als Kommentar hinterlassen.

Bilder mit css nicht vergrößern

Ich habe in meinen Blog inzwischen auch Bilder und ich nutze die NextGEN Gallery. Aus Platzgründen verkleinere ich die Bilder. Die Bilder, welche im Hochformat sind sehen einfach grausam aus, da sie stark vergrößert werden. Durch den folgenden Hack im css werden die Bilder nicht mehr vergrößert. Dazu muss man die Datei nextgen-gallery/css/nggallery.css wie folgt ändern:

.ngg-imagebrowser img {
    border: 1px solid #A9A9A9;
    display: block !important;
    margin: 10px auto;
    max-width: 100%;
    padding: 5px;
}

Achtung: Die Änderung geht bei einen automatischen Update des Plugins verloren!

Im SunStudio die STL nutzen

Mir ist die Tage beim programmieren negativ aufgefallen, dass sich im Sun Studio 12 Express einige Funktionen anderst sind, als in der STL spezifiziert. Mir ist es bei std::sort aufgefallen. Man kann normal sort eine Funktion übergeben, welche die Elemente vergleicht. Diese Überladung existiert in der Sun STL nicht. Das ist bekannt und wurde schon an anderen Stellen diskutiert. Wenn man die STL nutzen möchte, dann muss man dem Compiler die Option -library=stlport4 mitgeben, dann wird die standartkonforme STL verwendet.

Im Sun Studio kann man diese Option unter Additional Options mit angeben.

Nutzer anlegen im Active Directory

Ich habe vor einigen Tagen mich mit dem Active Directory beschäftigen müssen. Für mich als Solaris-User ist das eine ganz andere Welt. Deswegen habe ich mich sehr schwer getan, ohne Martin wär dieser Artikel nicht möglich gewesen. Er stand mir mit Rat und Tat eine Stunde telefonisch zur Verfügung. Danke noch einmal!

Nun zu meinen Problem: Ich wollte Nutzer aus einer spool-Datei automatisch in das Active Directory eintragen. Weiterhin mussten die Benutzer in die Organizational Unit peter_lustig_user verschoben werden. Das anlegen der Nutzer habe ich noch alleine hinbekommen. Dazu habe ich aus zahlreichen Skripten Codezeilen kopiert. Aber das Verschieben habe ich nicht hinbekommen. Martin hat mich auf die Active Directory Tools von Microsoft hingeweisen. Diese fangen alle mit ds an. Mit dsquery * habe ich mich durch die Struktur des Active Directory gewühlt. Das grafische Frontend ist zwar schön, aber da habe ich nicht mitbekommen, aber da weiß ich nicht wie der Distinguished Name aussieht…
Zum Schluss bin ich zu folgen Skript gekommen:

Set args = WScript.Arguments
profile_pfad = "\\odin\homes\%username%\profile"
gruppe_neu = "benutzer"
if args.count <> 1 then
	MsgBox "Es muss genau eine spool-Datei angegeben werden"
	Wscript.quit
End If
Randomize
protokoll = "C:\Dokumente und Einstellungen\Administrator\Desktop\skripte\protokoll.txt"
Set fs = CreateObject("Scripting.FileSystemObject")
' Das WScript.Network-Objekt liefert den Namen des Computers
Set net = CreateObject("WScript.Network")
' Protokolldatei öffnen
Set output = fs.CreateTextFile(protokoll, True)
'Holt den Namen des Computers aus dem net Objekt
name = net.ComputerName
Set computer = GetObject("WinNT://" & name)
' Datei öffnen
dateiname = args(0)
If Not fs.FileExists(dateiname) Then
	MsgBox "Die Datei (" & dateiname & ") existiert am angegebenen Ort nicht!"
	WScript.Quit
End If
Set infos = fs.OpenTextFile(dateiname)
' Datei zeilenweise bis zum Ende (atEndOfStream) lesen:
Do Until infos.AtEndOfStream
	' eine Zeile einlesen
	zeile = infos.ReadLine
	' Informationen durch Semikola splitten
	details = Split(zeile, ";")
	username = Trim(details(0))
	' Konto anlegen
	Set kontoneu = computer.Create("User", Trim(details(0)))
	kontoneu.FullName = Trim(details(1))
	kontoneu.Profile = profile_pfad
	' Passwort auslesen, wenn es das default-Passwort ist, dann generiere ein Passwort
	passwort =  Trim(details(2))
	if passwort = "du34!$7_.4-@" then
		passwort = Trim(genPasswort)
		kontoneu.PasswordExpired = CLng(1)
	end if
	kontoneu.SetPassword passwort
	' Ablaufdatum setzten
	if trim(details(3)) <> "never" then
		kontoneu.AccountExpirationDate = Trim(details(3))
	end if
	' Normales Benutzerkonto
	kontoneu.UserFlags = 512
	if not fs.FolderExists("\\odin\homes\" & username) then
		set folder = fs.CreateFolder("\\odin\homes\" & username)
		set folder_files = fs.createfolder("\\odin\homes\" & username & "\files")
		set folder_profile = fs.createfolder("\\odin\homes\" & username & "\profile")
		set IShellDispatch2 = CreateObject("Shell.Application")
		Call IShellDispatch2.ShellExecute("C:\skripte\subinacl", "/file \\odin\homes\" & username & " /setowner=" & username, , , 0)
		Call IShellDispatch2.ShellExecute("c:\skripte\subinacl", "/subdirectories \\odin\homes\" & username & " /setowner=" & username, , , 0)
		Call IShellDispatch2.ShellExecute("C:\skripte\cacls", "\\odin\homes\" & username & " /T /G Administratoren:F " & username & ":F System:F < echo j", , , 0)
	end if
	err.clear
	On Error Resume Next
	kontoneu.SetInfo
	if Err.number = 0 then
		WriteLog "Benutzername:  " & username & "   Passwort: " & passwort
		AddToGroup gruppe_neu, kontoneu.ADsPath
		' User in die ou peter_lustig_user verschieben
		set dsMove = CreateObject("Shell.Application")
		dsMoveArg = " " & Chr(34) & "CN=" & username & ",CN=Users,DC=w2k8-pool,DC=windows,DC=0rpheus,DC=net" & Chr(34) & _
	                       " -newparent " & Chr(34) & "OU=peter_lustig_user,DC=w2k8-pool,DC=windows,DC=0rpheus,DC=net" & Chr(34)
		Call dsMove.ShellExecute("dsmove", dsMoveArg, , ,0)
	else
		if Err.number = -2147022672 then
			WriteLog "Fehler beim Anlegen von " & username & ": Nutzer existiert bereits"
		else
			WriteLog "Fehler beim Anlegen von " & username & ": " & Err.Number
		end if
	end if
	Err.Clear
Loop
' Dateien schließen
infos.Close
output.Close
' Protokoll anzeigen:
'SYS: Microsoft (r) Script Runtime
Set wshshell = CreateObject("WScript.Shell")
wshshell.Run """" & protokoll & """"
Sub AddToGroup(gruppenname, kontoname)
	On Error Resume Next
	Set gruppe = GetObject("WinNT://" & ComputerName & "/" & gruppenname & ",group")
	gruppe.Add kontoname
	gruppe.SetInfo
	If Err.number = 0 Then
		'WriteLog "Konto ist Mitglied in Gruppe " & gruppenname
	Else
		'WriteLog "Konto konnte nicht zum Mitglied in Gruppe " & gruppenname & " gemacht werden."
	End If
	Err.Clear
End Sub
 
Sub WriteLog(text)
	' eine Zeile ins Protokoll schreiben und Leerzeile einfügen
	output.WriteLine text & vbCrLf & vbCrLf
End Sub
 
function genPasswort()
	password = ""
	for i=1 to 12
		if Int(100*Rnd mod 2 ) = 1 then
			password = password & chr(Int(61*Rnd+33))
		else
			password = password & chr(Int(29*Rnd+97))
		end if
	next
	genPasswort = password
end function

Der AD-Guru oder Windows-Hardcore User wird sicher sagen, wie dumm ist das denn, das geht in einen 3-Zeiler. Aber ich kann kein Windows und will es eigentlich auch nicht lernen :P Wenn ich Zeit hätte wüsste ich wie man mit den ds*-Tools das ganze schöner machen könnte. Ich habe das komplette Skript hier rein gestellt, da man sicher die ein oder andere Zeile klauen kann *g*. Der Passwortgenerator ist schlecht, es war aber die schnellste Lösung.

Shared memory Allocator mit der STL

Ich habe mich die letzten Tage mit der STL herungeärgert. Ich wollte einen Allocator schreiben, welcher mir die STL-Container in ein Shared Memory Segment legt. Ich habe es nicht wirklich hinbekommen. Inzwischen weiß ich, dass es die Leute von boost auch nicht hinbekommen haben. Aus diesem Grund werde ich nun boost benutzen und hoffen, dass die Performance nicht zu schlecht (unter Windows) ist. Das geheimnis ist, dass man die Container nach implementiert und die Implementierung kommt arbeitet korrekt in einem Shared Memory Segment.

“Sichere” Captchas programmieren

Man möchte manchmal Teile seiner Seite mittels Captchas schützen. Es gibt zahlreiche fertige Varianten, auch für wordpress. Diese haben fast immer den Nachteil, dass sie JavaScript, Flash, oder Sessions benutzen. Persönlich habe ich eine Abneigung gegen JavaScript und Flash. Sessions lassen sich nicht immer nachträglich nutzen und man erzeugt serverseitig etwas Last. Fakt ist, dass ich keine Sessions mag! Das schlimmste an fertigen Captcha-Lösungen ist der zum Teil invalide html-Code. Ich möchte validen xhtml 1.0 strict-Code haben und das Captcha sollte in mein Design passen. Wenn man die ganzen Anforderungen erfüllt haben möchte, so muss man wohl oder übel sein Captcha selbst programmieren.

Wie komme ich zum sicheren Captcha

Wenn ich auf Sessions verzichten möchte, so muss ich die Lösung des Captcha mit auf die Seite schreiben. Das kann man in einen nicht sichtbaren Feld machen. Damit man dieses Feld nicht so einfach auslesen kann, schreibt man einen Hash hinein bzw. man verschlüsselt den Inhalt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
define(KEY, "Ich bin ein Key");
define(IV, "KlyV6gxG3MOPzlfuj8azF6sKKTnsdsiN58i0zjHA0EU=");
 
function Crypt($plaintext){
    $td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
 
    $iv = base64_decode(IV);
    $ks = mcrypt_enc_get_key_size($td);
 
     /* Create key */
    $key = substr(md5(KEY), 0, $ks);
 
    /* Intialize encryption */
    mcrypt_generic_init($td, $key, $iv);
 
    /* Encrypt data */
    $encrypted = mcrypt_generic($td, $plaintext);
 
    /* Terminate decryption handle and close module */
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
 
    return base64_encode($encrypted);
}
 
function Decrypt($chiffre){
    $td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
 
    $iv = base64_decode(IV);
    $ks = mcrypt_enc_get_key_size($td);
 
     /* Create key */
    $key = substr(md5(KEY), 0, $ks);
 
    $chiffre = base64_decode($chiffre);
    mcrypt_generic_init($td, $key, $iv);
    $plaintext = mdecrypt_generic($td, $chiffre);
 
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
 
    return $plaintext;
}
 
function draw_captcha_form(){
    .....
    $time = time() + 60*30;
    $captchaSolution = "Test"
    echo "\t\n\tBitte Captcha lösen<br/>\n";
    // erzeuge ein Captcha
    echo "\t\n";
    echo "\t" . '
<input name="captvalue" id="captvalue" value="" size="40" tabindex="4" type="text"/>' . "\n";
    echo "\t"    . '
<input name="captcha" value="'. Crypt($time . "~" . $captchaSolution . "~" . $REMOTE_ADDR) . '" type="hidden"/>' . "\n";
}
 
function check_post($) {
    ....
    $captcha = $_POST['captvalue'];
    list($timeOld, $secret, $addr) = explode('~',Decrypt($_POST['captcha']));
    ....
    if($timeOld <= time()){
            echo "Deine Zeit ist abgelaufen";
            return;
    }
    if($addr != $REMOTE_ADDR){
            echo "Falsche IP";
            return;
    }
    if($secret != $captcha){
            echo "Falsches Captcha";
            return;
    }
    .....
}

Mit diesen Ideen kann man sich nun sein eigenes Captcha zusammen bauen. Ich generiere z.B. Matheaufgaben.