Yandex Search found malware on your website

Mit solchen Dingen muss man sich herumschlagen. Wer wie ich ein Blog über Spam führt, glaubt ja schon schnell erstmal gar nichts, aber die folgende Mail ist insofern »echt«, als dass sie wirklich von einem Server von Yandex kommt, auch gehen die angegebenen Links wirklich zu Yandex:

Betreff: Yandex Search found malware on your website spam.tamagothi.de

Hi,

Some of the pages on your website may pose a threat to your visitor’s computer security. The number of potentially harmful pages is 1. [sic! Sehr informativ, nicht?!] You can view the details of our malware scan at http://yandex.com/infected?url=spam.tamagothi.de&l10n=en. To learn about how to find malicious code and delete it from your pages, please go to the help section http://help.yandex.com/webmaster/?id=1115235#1115243 of our free website management service Yandex.Webmaster http://webmaster.yandex.com/.

Yandex is one of the world’s leading search engines and a popular web portal (http://company.yandex.com/general_info/yandex_today.xml). We continually check all websites in our search index using our own antivirus suite which integrates the signature and the behavioral approaches to malware detection. Read more about our antivirus technology at http://company.yandex.com/technologies/antivirus_technology.xml.

This is an automated message to alert you about a problem detected on your website. This service free [sic!] and does not require registration. [Man nennt solche alarmierenden, automatisch versendeten Nachrichten andernorts auch »Spam«, was angesichts der breit dargebrachten Reklame ein sehr passendes Wort dafür ist]

To receive additional information about your website, including the list of infected pages, or to request a check-up after the malicious code has been deleted, please register on our free website management service Yandex.Webmaster (http://webmaster.yandex.com).

Best regards,
Yandex Safe Search Team

[Alle Links sind von mir auf andere Ziele gesetzt worden. Wer verstehen will, warum ich diese Leute beim besten Willen nicht auch noch direkt verlinken mag, muss nur weiterlesen.]

Da ich gerade eben erst die Wucht der neuen Brut von Kommentarspamskripten erleben durfte, führt ein solcher Hinweis bei mir nicht gerade zu einem gleichgültigen Schulterzucken. Gerade das Spamblog hat bereits – neben dem »gewöhnlichen« DDoS-Vandalismus – einige durchaus gelungene Angriffe (meist auf ausbeutbare WordPress-Bugs) erlebt, die mir teils erhebliche Aufräumarbeiten bescherten. Deshalb habe ich mir auch diesen Hinweis zum Grund genommen, mir die Sache ganz genau anzuschauen.

Die »Details« des Malware-Scans von Yandex sind mir in dieser Absicht nicht gerade eine große Hilfe gewesen:

Screenshot der Details auf Yandex

Genau wie in der Mail gibt es nicht den geringsten Aufschluss darüber, welche Seite im Spamblog mit Malware verseucht sein soll, stattdessen einen Hinweis, dass die gesamte Domain für Besucher gefährlich sei. Nicht, dass ich diese Einstufung für eine schlechte Idee halte, ganz im Gegenteil. Aber für mich als denjenigen, der auf der webmaster-Adresse einen solchen Hinweis erhält, fehlt in dieser »Information« irgendwie die Information.

Mein nächster Weg führte mich erstmal zu Googles Webmaster-Tools. Auch Google führt regelmäßig einen Scan auf Malware durch, bei dem ich schon einmal lernen musste, dass auch das Zitat eines HTML-Quelltextes in einer Textdatei gefährlich ist, weil einige Browser aus dem Hause Microsoft sich nicht um den vom Server gelieferten MIME-Type kümmern, sondern (in Verletzung von Webstandards) automatisch eine HTML-Darstellung machen und den schädlichen Code dabei ausführen. Gut, Dateien löschen ging schnell, und schon waren auch die letzten Nutzer älterer Versionen des Internet Exploiter geschützt. Google hat dabei für mich den großen Vorteil, dass die URL mit dem gefährlichen Code auch genannt wird, so dass ich eine gute Chance habe, ein gefundenes Sicherheitsrisiko so schnell wie möglich zu beseitigen. Dafür werde ich auf der anderen Seite nur dann mit Mail belästigt, wenn ich das explizit will. Zwei Dinge, von denen Yandex vielleicht etwas lernen sollte… :mrgreen:

Aber die Webmaster-Tools von Google haben auf »Unser täglich Spam« keine Malware gefunden. Vermutlich verwenden sie nicht »our own antivirus suite which integrates the signature and the behavioral approaches to malware detection« mit Sophos-Reklame in etlichen Yandex-Seiten, sondern ein Verfahren, das zuverlässig ist. Zumal der Ansatz bei Yandex… ähm… interessant ist:

The Yandex antivirus technology, on the other hand, is based on an alternative, “behavioral” approach. The idea behind it is that the program detects malware by performing the actions similar to those of a visitor to a web page. If a download or a program execution begins on a page automatically without user initiation, this page is very likely to be infected. This method allows detecting malware anywhere on the page including external code, such as the code of a banner ad. The main advantage of the behavioral approach is its ability to detect viruses that haven’t yet been added to any antivirus database.

Nur hilfreich zum Eingrenzen der Suche ist das alles nicht. Oh, es gibt ja auf der Yandex-Warnseite noch einen kleinen Link für »Weitere Informationen«, mal klicken:

More information -- Yandex periodically checks websites for viruses. The last check (less than two days ago) detected malware on this website. The owner of the site may be completely unaware of any malicious code installed on the site by hackers. If the code is not found the next time the website is checked the tag will be removed. -- Malware: contains Troj/Iframe-EZ (data provided by Sophos).

Hui, schon wieder Sophos, für die dieser Code schon ein alter Bekannter ist. Um was für einen Trojaner es sich handelt, sagt mir Sophos in seiner uninformativen Dreckssite für Schlangenölkäufer genau so wenig, wie Yandex mir sagt, unter welcher URI sein Bot den Trojaner gefunden haben will. Gut, dass Microsoft da wesentlich informativer ist und dass SecureList zeigt, dass da wirklich eine sehr allgemeine Warnung zu einem schrillenden, roten Alarm geführt hat. So langsam glaube ich ja, dass das kein Hinweis auf Malware in meinem Blog, sondern eine tolle neue Reklameform für das Antivirus-Schlangenöl¹ von Sophos ist, die allerdings für mich nicht so ganz gelungen herüberkommt. In welchem der über 2.300 Blogpostings auf »Unser täglich Spam« die Malware stecken soll, wäre für mich in einer derartigen Situation eine viel wichtigere Information, damit ich überhaupt eine Gelegenheit bekomme, die mögliche Gefahr schnell zu sichten und gegebenenfalls zu entfernen. Aber darauf scheint es bei dieser Mail nicht anzukommen…

Es gibt da schon einige IFRAMEs in »Unser täglich Spam«, die möglicherweise für den tollen Yandex-Algorithmus interessant sind, da sie externen Code enthalten und ausführen (eventuell sogar mit Download größerer Datenmengen). Dies sind einige YouTube-Videos, einige Dailymotion-Videos und die Mailinator-Ansicht des Gammelfleisch-Honigtöpfchens auf der Seite »Gib mir Spam« mit einer hoffentlich ausreichend klar formulierten Warnung, was es mit den dort sichtbar werdenden Spammails auf sich hat.

YouTube und Dailymotion vertraue ich, und in der Tat, die Mailinator-Ansicht sollte vielleicht besser nicht von Suchmaschinen indiziert werden, da sie ohne den allgemeinen Kontext von »Unser täglich Spam« möglicherweise ein bisschen gefährlich ist. Das ist zum Glück ein Problem, das sich sehr einfach lösen lässt – denn die meist schlampig hingehackten Harvester der Spammer werden sich ganz sicher nicht an Regeln in einer robots.txt halten, aber die Bots jeder seriösen Suchmaschine halten sich selbstverständlich daran.

Dies war die einzige Seite mit externen Code in einem IFRAME, dem ich nicht restlos vertrauen kann. Nach einem kurzen Überfliegen der darin verbauten JavaScript-Basteleien bin ich allerdings ein kleines bisschen beruhigter – das ist Standard-Code, der Inhalte in einem zunächst unsichtbaren weiteren IFRAME lädt, um diesen dann sichtbar zu machen.

Aber das alles ist noch lange kein Grund, sich zurückzulehnen, denn dafür ist so eine Warnung doch deutlich zu ernst. Das, worauf ich am wenigsten Lust habe, ist es, zum Helfershelfer für die organisierte Kriminalität im Internet zu werden.

Und deshalb hielt ich noch ein bisschen mehr Analyse für erforderlich.

Natürlich habe ich mir zuerst den HTML-Quelltext verschiedener Blogseiten angeschaut, ohne etwas Verdächtiges zu bemerken. Angesichts einer angeblich »infizierten« Seite in einer so großen Website ist das allerdings wie die Suche nach der Nadel im Heuhaufen.

Die zweite Sache, die ich untersucht habe, ist das Upload-Verzeichnis von WordPress. Es gab in der Vergangenheit immer wieder einmal Sicherheitsprobleme, die einen Upload ermöglichten, und ein solcher Upload kann leicht von außen verlinkt werden, um anderen Leuten Malware unterzujubeln. Ein grep -R -i iframe brachte allerdings keine einzige Datei zutage, die ein IFRAME enthielt. Und weil ich gerade dabei war, habe ich das gleiche vorsichtshalber im Theme-Verzeichnis wiederholt – mit dem gleichen Ergebnis. Schließlich habe ich mich mit einem find . -mtime -8 | grep -v supercache davon überzeugt, dass es in den letzten acht Tagen nicht zu einer auffälligen Modifikation von Dateien der WordPress-Installation kam. Sehr beruhigend, dass die WordPress-Installation vermutlich unbeschädigt ist und dass kein bislang wenig bekanntes Sicherheitsloch ausgebeutet wurde.

Aber es gibt natürlich noch mehr Angriffspunkte.

Bei einem wirklich grimmig vorgetragenen Angriff könnte sich ein Angreifer einen administrativen Zugang zum Serverrechner beschaffen und direkt den Webserver oder den PHP-Interpreter angreifen. Zum Beispiel könnte er dafür sorgen, dass Fehlerseiten (wie der 404er, File not found) durch eigene Seiten ersetzt werden. Also war ein kurzer Blick in die Konfiguration des Webservers nötig, um diese Quelle auszuschließen. Ein weiterer Angriffspunkt ist die Konfiguration des PHP-Interpreters. Hier könnten etwa die Einstellungen auto_preprend_file und auto_append_file manipuliert werden, um an jede ausgelieferte PHP-Seite Inhalte anzuhängen. Auch das war zum Glück nicht der Fall, denn sonst hätte ich jetzt viel damit zu tun, einen erfolgreichen Angriff zu analysieren und die ausgebeutete Lücke zu schließen.

Da es sich mit hoher Wahrscheinlichkeit nicht um eine hochgeladene Datei, nicht um eine beschädigte WordPress-Installation und nicht um eine Manipulation der Konfiguration des Webservers handelt, muss der fragliche Code also in einem der Postings zu finden sein – und diese liegen in einer MySQL-Datenbank.

Also ist zu guter Letzt eine kleine SQL-Query fällig, um einmal einen Blick auf die Beiträge zu werfen, die das Wort IFRAME enthalten. Erstmal ein Überblick, wie viele es wohl sein werden:

mysql> SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE ’%iframe%’;

Zu meinem Glück waren es nur 34. (Wer das nicht weiß: Ein Stringvergleich mit LIKE in der MySQL ist case-insensitiv. Alles andere wäre für einen Mustervergleich auch eher unpraktisch, und wo schon SQL niemals unpraktisch sein wollte, setzen die Standardabweichungen des MySQL-RDBMS noch einen drauf²…)

Und auf gehts in die Handarbeit! Das sind genau die Dinge… 🙁

Nach der Durchsicht von 34 Postings (natürlich nicht im WordPress-Backend, sondern nach Absetzen einer Query in einem guten Editor) bin ich guter Dinge, dass es sich bei der Yandex-Meldung um einen Fehlalarm handelt.

Insgesamt hat mich dieser Mist nicht nur eine Menge Nerven gekostet, sondern auch zweieinhalb Stunden meiner Lebenszeit (das Schreiben dieser Zusammenfassung nicht mitgerechnet), die ich lieber mit angenehmeren oder doch wenigstens konstruktiveren Tätigkeiten verbracht hätte. Was ich nach dieser Erfahrung von Dingen halte, die mir mit der Firmierung Yandex oder Sophos über meinen Weg laufen, kann sich hoffentlich jeder selbst vorstellen.

Haben sie selbst eine derartige Mail erhalten?

Meiner etwas gereizten Schilderung können sie entnehmen, dass Malware-Warnungen für Websites von Seiten Yandex’ zumindest manchmal etwas leichtfertig per unverlangter Mail versendet werden. Sie sind desweiteren für den Menschen, der sie empfängt, vollkommen nutzlos, da sie ihn nicht darin unterstützen, die Quelle des Problemes aufzufinden und das Problem zu beseitigen, ganz so, als sei das nicht die Hauptsache. Dies geht einher mit einem alarmierenden Ton und der Aufforderung, Dienste von Yandex zu benutzen und sich zu diesem Zweck unter Preisgabe persönlicher Daten zu registrieren.

Die gesamte Form dieser Mail ist unseriös und hart an der Schwelle zur klaren Spam.

Ich kann nicht beurteilen, ob solche Warnungen auch für ernsthafte Bedrohungen in gecrackten Websites versendet werden, oder ob es sich um eine reine Spam- und Werbemasche handelt. Ich weiß nur, dass ich persönlich niemals wieder einen Hinweis aus dieser Quelle so ernst nehmen werde, dass ich mir die Dinge sehr genau anschaue. Die Vorstellung, dass auch Menschen solche nichtsnutzigen Hinweise erhalten, die sich nicht selbst zu helfen wissen, widert mich an. Der Firma Sophos lege ich, wenn sie noch einen Rest guten Rufes behalten will, dringend nahe, ihre Firmierung aus derartigen Machenschaften herauszuhalten.

Wenn sie eine solche Warnung von Yandex bekommen haben, bewahren sie erstmal Ruhe und prüfen sie, ob ihre Website auch von anderen Dienstleistern als potentiell gefährlich eingestuft wird. Und wenn nicht, machen sie mit Mails von Yandex genau das gleiche, was ich ab jetzt auch damit mache: Ab in den virtuellen Mülleimer, wo schon die ganze andere Spam liegt. Da ist sie in der richtigen Gesellschaft.

¹Ja, Antivirus-Software ist Schlangenöl. Der Versuch, ein werksmäßig unsicheres Biest wie Microsoft Windows durch Installation zusätzlicher Software abzusichern, wenn diese Software nur Schädlinge findet, die schon ein paar Tage bekannt sind, führt sogar zu einer gefährlichen gefühlten Sicherheit, die geeignet ist, unbedarfte Menschen zur Unvorsicht zu reizen. Es kann für Menschen, die mit Microsoft Windows arbeiten müssen oder wollen, eine Ergänzung sein, es ist aber kein Ersatz für die Benutzung des Gehirnes. Bedrohungen aus dem Internet lassen sich wesentlich effektiver bekämpfen, indem man erstens niemals in eine Spam klickt und zweitens nicht jeder Website die Ausführung von JavaScript und Plugin-Code gestattet und dafür geeignete Hilfsmittel als Browserplugins installiert.

²Hier stand ursprünglich – und das war mein Fehler – das der LIKE-Operator standardmäßig caseinsensitiv ist. Mein Kommentator Thomas hat mich auf diesen Fehler hingewiesen, den ich dann korrigiert habe.

Veröffentlicht unter Bloggen, Technisches | Verschlagwortet mit , , , , | 6 Kommentare

Zeitansage

Weil jemand kürzlich ganz erstaunt darüber war, dass meine Rechner jede Viertelstunde automatisch die Zeit ansagen, verrate ich zu gern, wie ich das gemacht habe.

Zunächst einmal zur Motivation. Es ist für mich relativ leicht, am Computer die Uhrzeit zu vergessen. Ja, ich lasse mir die Zeit mit einem Widget in einem Xfce-Panel anzeigen, aber wenn ich so konzentriert auf eine Sache bin, dass ich darüber die Zeit vergessen könnte, schaue ich dort natürlich nicht hin. Deshalb habe ich gern ein kleines Signal, das ich wahrnehmen kann, ohne dass es meine Aufmerksamkeit mit allzuviel Gewalt an sich reißt.

Natürlich ist der hier skizzierte Weg so nur unter Linux gangbar.

Für mich war es sehr naheliegend, einfach in regelmäßigen Abständen die Uhrzeit sprechen zu lassen. Für die Sprachsynthese verwende ich espeak, weil das auf den Debian- und Ubuntu-Installationen, auf denen ich arbeite, in aller Regel schon installiert ist. So kann ich trotz wechselnder Arbeitsrechner meine Skripte ohne Änderung nahezu überall benutzen, ohne dass ich etwas nachinstallieren müsste. Wer lieber ein anderes Programm verwendet – espeak liefert nicht gerade eine hübsche Sprachausgabe – wird nach Lesen der entsprechenden man-page für sein Lieblingsprogramm schon herausbekommen, wie sich mein kleines Hackwerk anpassen lässt.

Die von mir hingehackten Skripten sind recht »quick and dirty«, es sind also keine Meisterwerke der Softwareentwicklung. Aber sie funktionieren für den vorgesehenen Zweck gut.

Eine ganz einfache Lösung

In meiner ersten Version hat das Skript einfach gesagt: »Es ist jetzt 13 Uhr 22″. Wer eine solche Ansage gut genug findet, kann das mit sehr wenig Mühe erreichen:

#!/bin/sh

date +’$H $M’ | 
awk ’{ printf "Es ist jetzt %d Uhr %d", $1, $2 }’ |
espeak -v de 2>/dev/null

Dieses bemerkenswert primitive Shellskript spricht bei Aufruf die Uhrzeit in der Form »Es ist jetzt zehn Uhr sechsundfünfzig«. Für Menschen, die mit Digitaluhren großgeworden sind und die Uhrzeit niemals anders bezeichnen, ist das völlig hinreichend – vor allem, wenn sie sich nicht an Fehlerchen wie »Es ist jetzt eins Uhr null« stören. Es könnte etwa in die crontab eingetragen werden, um alle fünfzehn Minuten die Zeit anzusagen – wobei vielleicht Vorsorge getragen werden sollte, damit es das nur tut, wenn man selbst angemeldet ist. (Siehe hierzu weiter unten).

Das stellt mich aber nicht zufrieden…

Ich bin nun schon ein etwas älterer Mensch, mit Analoguhren großgeworden und bevorzuge deshalb die althergebrachte, ausführliche Bezeichnung der Uhrzeit. Anstelle von »Es ist jetzt zehn Uhr sechsundfünfzig« würde ich lieber »Es ist jetzt vier Minuten vor elf« hören, weil ich das sofort und ohne weiteres Nachdenken auffassen kann. Dies natürlich mit den üblichen Besonderheiten zu den Viertelstunden, den halben Stunden und zu den vollen Stunden und allen damit verbundenen sprachlichen Unregelmäßigkeiten.

Tja, und das alles erfordert doch ein bisschen mehr Nachdenken als das zuvor kurz angerissene, einfache und zudem leicht fehlerhafte Shellskript.

Weil ich sehr genau weiß, dass sich niemand solche Gedanken gern macht, gibt es meine Skripten hier zum freien Download – wer unbedingt eine Lizenz dafür zu brauchen glaubt, fühle sich unter den Bedingungen der Piratenlizenz lizenziert… 😉

Ausgabe der Uhrzeit als deutscher Text

Ich bin das Problem in zwei Schritten angegangen.

Als erstes habe ich ein kleines Programm geschrieben, dass die Uhrzeit in deutscher Sprache als Text ausgibt. Dabei gebe ich auch Zahlwörter als Text aus, damit immer die richtig deklinierten Zahlwörter verwendet werden.

So ein Programm kann man natürlich auch – wie die sehr einfache Lösung oben – in awk schreiben, wenn man zur Selbstquälerei neigt. Angesichts der vielen Ausnahmen habe ich mich aber für das syntaktisch deutlich verständlichere Python entschieden; ich wollte schließlich für so eine Kleinigkeit nicht übermäßig viel Zeit mit Fehlersuche verbringen.

Dieses Python-Programm sieht nur auf dem ersten Blick etwas abstoßend aus, weil es für seinen sehr einfachen Zweck doch sehr lang geraten ist. Diese Länge spiegelt die Unregelmäßigkeiten und die Unlogik gesprochener Sprache wider:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime

einer = [
    ’null’,
    ’eins’, ’zwei’, ’drei’, ’vier’, ’fünf’,
    ’sechs’, ’sieben’, ’acht’, ’neun’, ’zehn’,
    ’elf’, ’zwölf’, ’dreizehn’, ’vierzehn’, ’fünfzehn’,
    ’sechzehn’, ’siebzehn’, ’achtzehn’, ’neunzehn’
]

zehner = [
    ’null’,
    ’zehn’, ’zwanzig’, ’dreißig’,
    ’vierzig’, ’fünfzig’, ’sechzig’
]

def i2de(n):
    assert n >= 0
    if n < 20:
        return einer[n]
    else:
        z = n / 10
        e = n % 10
        if e == 0:
            return zehner[z]
        else:
            if e == 0:
                return zehner[z]
            elif e == 1:
                return ’einund%s’ % (zehner[z],)
            else:
                return ’%sund%s’ % (einer[e], zehner[z])
        
def chour(h):
    if h >= 12:
        h -= 12
    if h == 0:
        h = 12
    return i2de(h)

def datetime2text(dt):
    st=dt.hour
    mi=dt.minute
    if mi % 15 == 0:
        if mi == 15:
            return ’Viertel nach %s’ % (chour(st),)
        elif mi == 30:
            return ’Halb %s’ % (chour(st+1),)
        elif mi == 45:
            return ’Viertel vor %s’ % (chour(st+1),)
        elif mi == 0:
            if st == 1:
                return ’ein Uhr’
            else:
                return ’%s Uhr’ % (chour(st),)
    else:
        if mi == 1:
            return ’eine Minute nach %s’ % (chour(st),)
        elif mi == 59:
            return ’eine Minute vor %s’ % (chour(st + 1),)
        elif mi < 30:
            return ’%s Minuten nach %s’ % (i2de(mi), chour(st))
        else:
            return ’%s Minuten vor %s’ % (i2de(60 - mi), chour(st + 1))

if __name__ == ’__main__’:
    print(datetime2text(datetime.datetime.now()))

Wer es verstehen möchte: Es ist viel einfacher, als man denkt.

Die Funktion i2de ist eine allgemeine Funktion, die aus einem int ein Zahlwort macht – hier natürlich mit sehr beschränktem Gültigkeitsbereich. Die Arrays mit den Zahlwörtern bieten sich natürlich an (und sie sind hier etwas weiter befüllt, als dies nötig ist). Die Funktion chour löst das Problemchen, dass die Stunde zwar modulo 12 ausgegeben werden soll, dass aber andererseits null Uhr zu zwölf Uhr wird. Die eigentliche Arbeit wird in datetime2text getan; hier gibt es eine Menge Sondercode für die vollen Viertelstunden, für die Zahl eins mit ihren Deklinationen und schließlich wird noch zwischen nach der letzten Stunde oder vor der nächsten Stunde unterschieden. Das ist übrigens der Grund, weshalb ich nach sehr kurzem Nachdenken awk verworfen habe… 😉

(Und ja, natürlich kann man das auch gut in Perl machen. Nur awk würde ich in diesem Fall nicht empfehlen. Außer bei vorhandenem Hang zur Selbstquälerei.)

Wenn dieses Skript – ich habe es unter dem naheliegenden Dateinamen uhrzeit gespeichert – aufgerufen wird, gibt es die aktuelle Uhrzeit als Text aus. Nur fehlt nur noch, dass dieser Text vorgelesen wird.

Vorlesen der Uhrzeit

Das Skript zum Vorlesen der Uhrzeit ist nun allerdings trivial:

#!/bin/sh

PATH=/bin:/usr/bin
if who -u | grep -q ’^elias’
then
    echo ’Es ist jetzt’ `/home/elias/bin/uhrzeit` |
    espeak -v de -s 120 2>/dev/null &
fi

Natürlich muss der Pfad zum Skript uhrzeit angepasst werden, und natürlich muss der grep auf den eigenen Benutzernamen gehen. Beide Anpassungen sind einfach.

Dieser grep zusammen mit dem who -u sorgt übrigens dafür, dass es nur dann zur Sprachausgabe kommt, wenn ich auch eingeloggt bin. Sicher, wenn ich das Skript von Hand aufrufe (oder durch einen Klick starte), ist das immer der Fall, aber es steht im Zusammenhang mit dem abschließenden Schritt.

Und jetzt jede Viertelstunde

Denn ich wollte ja, dass mir jede Viertelstunde automatisch die Zeit angesagt wird, wenn ich angemeldet bin.

Dazu habe ich das Shellskript zum Vorlesen der Uhrzeit – das ich unter dem ebenfalls naheliegenden Namen sagzeit gespeichert habe – in meine crontab eingetragen.

Einmal crontab -e getippt und mit meinem Lieblingseditor die folgende Zeile eingefügt:

*/15 * * * * /home/elias/bin/sagzeit

Nach dem Speichern und dem Beenden des Editors wird mein Skript sagzeit zu jeder vollen Viertelstunde ausgeführt. Da dies auch geschieht, wenn der Rechner hochgefahren ist, ich aber nicht angemeldet bin, ist jetzt klar, was der Zweck der zusätzlichen Bedingung im Shellskript ist: Die Kiste soll nicht einfach unerwünscht die Uhrzeit brabbeln, sondern es nur für mich tun.

Näheres zum Format der Datei lässt sich mit man 5 crontab in Erfahrung bringen, und wer noch nie davon gehört hat, sollte das ruhig einmal tun. Es ist ausgesprochen nützlich, Dinge automatisieren zu können. Schließlich ist der Computer dafür da, dem Menschen zu dienen und nicht umgekehrt.

Tja, und das ist Grund, warum ich so gern unixoide Betriebssysteme vor mir habe… 😉

Veröffentlicht unter Download | Verschlagwortet mit , , , | 3 Kommentare

Fraktalanimationen mit Xaos erstellen

Das ist ja geil, wie du deine Fraktalzooms schnell an der Kommandozeile machst. Kannst du mir das Programm geben?

Ja, das ist geil, denn da sind die Konzepte unixoider Betriebssysteme so richtig an der Arbeit, um mir die leidige und fehleranfällige Arbeit abzunehmen.

Das »Programm« ist ein einfaches Shellskript, das eine Menge fertiger Arbeit anderer Menschen nutzbar macht. Die Länge des unterlegten Musikstückes bestimme ich mit Sox, was übrigens generell ein unentbehrliches Tool für Menschen ist, die öfter einmal Sounddateien zu konvertieren haben und lieber dem Rechner bei der Arbeit zuschauen als sich die Finger wund zu klicken. Die einzelnen Bilder der Animation lasse ich mit Xaos berechnen, damit lege ich auch (schön klickig) den Start- und Endpunkt der Reise durch Fraktalia fest. Zum Glück kann man Xaos skripten, so dass dieser Teil der Arbeit bereits erledigt ist – sonst müsste ich für jedes Bild eine einzelne Parameterdatei erzeugen. Abschließend setze ich aus den Bildern und der Musik ein Video mit FFmpeg zusammen, einem geradezu mörderischen, kleinen Tool, dessen man-page mir jedes Mal aufs Neue zeigt, dass ich überhaupt nichts von Videoformaten zu verstehen scheine.

Mir wurde es irgendwann zu lästig, diesen Vorgang immer wieder händisch zu machen (und dabei auch immer wieder einmal eine neue Fehlerquelle zu finden), und deshalb habe ich mein Shellskript geschrieben. Dieses sieht für »normale« Menschen auf dem ersten Blick ein bisschen gruselig aus, was daran liegt, dass es sich um ein Programm handelt, das ein Programm erzeugt – dabei kommt es nicht gerade zur hübschesten Syntax. Dieses Skript sieht so aus (ich habs eben etwas aufgeräumt):

#!/bin/sh
########################################################################
#
# zoomskript
# $Id: zoomskript,v 1.3 2012/09/22 15:38:03 elias Exp $
#
# Aus einer Audio-Datei (diese gibt die Länge vor), zwei gespeicherten
# Parameterdateien von Xaos und einem Namen wird ein Skript erzeugt, das
# einen Fraktalzoom berechnet. Ich habe dabei so häufig Fehler gemacht,
# dass ich diese Aufgabe lieber an einen Computer übergebe. Der kann
# das nämlich besser als ich... 
#
# Alle vier Parameter sind erforderlich.
#
########################################################################

# Paranoiazeilen
PATH=/bin:/usr/bin
SOX_OPTS=""

# Parameter lesen, Kurzinfo bei falscher Anzahl 
case $# in
    4) 	xaosfrom="$1"
        xaosto="$2"
        music="$3"
        zoomname="$4"
        ;;
    *) 	echo "Aufruf: `basename $0` [xaos-from] [xaos-to] [audiofile] [name]"
        echo
        echo "* Schreibt zwei Dateien: [name].xpf und [name].sh"
        echo "* [name].xpf ist die Zoom-Definition für xaos"
        echo "* Filter und Palette werden aus [xaos-to] genommen"
        echo "* [name].sh ist das Shellskript, das das Video rendert"
        exit
        ;;
esac

# Die Namen der erzeugten Dateien
xaoszoom="$zoomname.xpf"
xaosskript="$zoomname.sh"

# Ein paar Zeilen langweiliger Fehlerbehandlung
if [ ! -f "$xaosfrom" ]
then
    echo >&2 "Keine Startpunkt-Definition ’$xaosfrom’"
    exit 1
fi
if [ ! -f "$xaosto" ]
then
    echo >&2 "Keine Endpunkt-Definition ’$xaosto’"
    exit 1
fi
if [ ! -f "$music" ]
then
    echo >&2 "Keine Audiodatei ’$music’"
    exit 1
fi
if [ -f "$xaoszoom" ]
then
    echo >&2 "Ausgabedatei ’$xaoszoom’ existiert bereits"
    exit 1
fi
if [ -f "$xaosskript" ]
then
    echo >&2 "Ausgabeskript ’$xaosskript’ existiert bereits"
    exit 1
fi

# Die Länge der Audiodatei mit sox ermitteln und daraus die
# Anzahl der Mikrosekunden für xaos ermitteln
musicmicros=`sox --info "$music" |
grep ’uration’ |
sed ’s/^[^0-9]*\([0-9\.:]*\).*$/\1/
     s/[:\.]/ /g’ |
awk ’{ sec = $4 / 100 + $3 + $2 * 60 + $1 * 60 * 60
       microsec = sec * 1000000
       printf "%d", microsec }’`

# Keine Länge ermittelt? Das ist ein Fehler!
if [ -z "$musicmicros" ]
then
    echo >&2 "Länge für Audiodatei ’$music’ kann nicht ermittelt werden"
    exit 1
fi

# Startpunkt aus der Startdatei ermitteln
startline=`grep ’^ *(view’ $xaosfrom |
sed ’s/).*$/)/
     s/^[^(]*(/(/’`

# Kein Startpunkt ermittelt? Das ist ein Fehler!
if [ -z "$startline" ]
then
    echo >&2 "In ’$xaosfrom’ existiert keine view-Zeile"
    exit 1
fi

# Zoomdatei schreiben
(   echo "; Diese Datei wurde automatisch mit `basename $0` erzeugt"
    echo "; Aufruf: `basename $0` \"$1\" \"$2\" \"$3\" \"$4\""
    echo
    sed "/^;/d
         s/(view/$startline\n(morphview/" <"$xaosto" 
    echo "(usleep $musicmicros)" ) >"$xaoszoom"

# Zoomskript schreiben
# Achtung! Ich setze eine gediegene Bitrate beim Erzeugen des Videos,
# weil ich der Meinung bin, dass man immer noch nachträglich die
# Qualität verschlechtern kann. Nachträgliches Verbessern hingegen ist
# eher ein bisschen schwierig...
cat >"$xaosskript" <<EOF
#!/bin/sh
# Dieses Skript wurde automatisch mit `basename $0` erzeugt
# Aufruf: `basename $0` "$1" "$2" "$3" "$4"

if [ -d /var/tmp ]
then
    tmpdir=/var/tmp/zoom-\`whoami\`-\$$
else
    tmpdir=/tmp/zoom-\`whoami\`-\$$
fi

trap "rm -rf \$tmpdir; exit" 1 2 15
mkdir \$tmpdir

nice xaos -render "$xaoszoom" \\
          -size 1280x720 \\
          -antialiasing \\
          -rendervectors \\
          -renderframerate 25 \\
          -basename \$tmpdir/img

nice ffmpeg -y \\
            -i "$music" \\
            -f image2 \\
            -i "\$tmpdir/img%04d.png" \\
            -r 25 \\
            -s hd720 \\
            -b 17000k \\
            "$zoomname.mp4"

rm -rf \$tmpdir
EOF

# Aufräumen
chmod +x "$xaosskript"

# Abschließender Hinweis
echo "Starte das Rendern mit ./$xaosskript"

Abschreiben oder übers Clipboard kopieren ist nicht nötig, hier ist ein bequemerer Download. Einfach herunterladen, entpacken und irgendwo in den $PATH legen. Wer auf Sicherheit bedacht ist, wird mir nicht vertrauen und natürlich einen Blick auf das Skript werfen wollen.

Ein erheblicher Teil besteht aus der Behandlung naheliegender Fehler, um einigermaßen verständliche Fehlermeldungen zu bekommen.

Wenn die verwendeten Tools sox und ffmpeg installiert sind, ist die Verwendung des Skriptes ganz einfach. Angenommen, die Musik befindet sich in der Datei soundtrack.wav, der Startpunkt der Animation in start.xpf und der Endpunkt in ende.xpf, und daraus soll ein Video namens blah.mp4 gemacht werden, dann gibt es die folgende Sitzung an der Kommandozeile:

ich@rechner ~/zoom $ zoomskript start.xpf ende.xpf soundtrack.wav blah
Starte das Rendern mit blah.sh
ich@rechner ~/zoom $ ./blah.sh

Den Rest erledigt jemand für mich, der es besser kann als ich: Der Rechner. 😉

So muss das auch sein!

Die Palette für die Animation und eventuelle Filter werden dabei aus der Zielposition übernommen, entsprechende Angaben der Startparameter werden vollständig verworfen. Das liegt daran, dass ich selbst lieber am Ziel (oder auf dem Weg dorthin) über solche Dinge entscheide.

Ach ja: Wer gern einen Lizenztext zu diesem Skript haben möchte, fühle sich bitte einfach unter den Bedingungen der Piratenlizenz lizensiert. Share and Enjoy, but don’t sue me!

Veröffentlicht unter Technisches | Verschlagwortet mit , , | Schreib einen Kommentar

Wpcmd 0.6

Nachdem ich mich mit einigen verbliebenen Fehlern herumgeärgert habe, war es wieder an der Zeit, eine neue Version von wpcmd zu veröffentlichen. Große Änderungen gibt es nicht, aber Abhilfe gegen kleine Ärgernisse.

Unter anderem haben viele Menschen, die ein bei wordpress.com gehostetes Blog betreiben, ein sehr ärgerliches Verhalten in wpcmd gefunden. Nachdem wordpress.com die XMLRPC-URL auf TLS-Verschlüsselung (HTTPS) umgestellt hatte, war es nicht mehr möglich, ein Blog zu revalidieren. Dies war jedoch erforderlich, um geänderte Kategorien auch für wpcmd bekannt zu machen, damit geeignete Vorlagedateien erstellt werden können.

Der Fehler lag darin, dass ich die XMLRPC-URL intern verwendet habe, um ein Blog zu identifizieren. Diese enthielt natürlich auch das Protokollschema https:, so dass das Revalidieren scheiterte und die neuen Kategorien nicht mehr ermittelt werden konnten. Eine schlechte Entscheidung, wie ich bemerken musste… 😉

Dieser Fehler gehört der Vergangenheit an. Desweiteren gibt es jetzt eine Option -K, um den Kategorienbaum neu von WordPress anzufordern, ohne dass eine vollständige Revalidierung erforderlich ist. Hinterher ist die Frage, warum man da nicht vorher dran gedacht hat, natürlich leicht zu stellen…

Desweiteren gibt es auch interne Änderungen. Bislang enthielt wpcmd eine Menge Code, der darauf vorbereiten sollte, eine Version zu erstellen, die sowohl mit Python 2.x als auch mit Python 3.x läuft – dieses Unterfangen hat sich jedoch als schwieriger erwiesen, als ich vorher gedacht habe. Deshalb habe ich diesen Code vollständig entfernt, um diese unnütze, das Lesen und Anpassen erschwerende Schicht zusätzlicher Komplexität aus dem Quelltext zu nehmen. Ich werde erst dann an eine Version für Python 3 denken, wenn Debian Stable mit Python 3 als Standardversion ausgeliefert wird.  Bis dahin ändert sich aus Benutzersicht nichts, denn nach wie vor läuft wpcmd mit Python 2. Bei der Installation wird ein installiertes Python 2 auch dann gefunden und benutzt, wenn Python 3 von der Linux-Distribution als Vorgabe verwendet wurde, weil ich vom populären Ubuntu einen derartigen Schritt für die nächste Zeit erwarte. Vernünftige Menschen nehmen eh die LTS-Version von Ubuntu und werden noch lange Zeit Ruhe vor derartigen »Beglückungsideen« haben.

Wie immer gibt es eine gute und auf den aktuellen Stand angepasste HTML-Dokumentation in deutscher und englischer Sprache sowie natürlich eine englischsprachige man-page. Die HTML-Dokumentation lässt sich bequem lesen, indem wpcmd -D an der Kommandozeile abgesetzt wird. Sie richtet sich explizit an Menschen mit geringem technischen Hintergrund, die ihre Blogbenutzung teilweise oder ganz automatisieren wollen oder die – wie ich – lieber ihre Texte mit HTML-Markup in ihrem Lieblingseditor als im doch recht fetten WordPress-Dashboard verfassen möchten.

Download-Link: wpcmd 0.6 (143,6 KiB).

Veröffentlicht unter Download | Verschlagwortet mit , | Schreib einen Kommentar

Wenn das »Leistungsschutzrecht« in Kraft tritt…

Wenn – was leider trotz der vollständigen Idiotie dieses Standesrechtes zum Schutz gescheiterter Geschäftsmodelle zu befürchten ist – das so genannte »Leistungsschutzrecht« demnächst in Kraft treten wird, dann werde ich mich nicht mehr groß aufregen, denn ich habe mich vorbereitet. Ich werde ganz einfach ein Terminal öffnen und nur eine kurze Zeile tippen:

$ sudo cat blacklist-0.2.txt >>/etc/hosts

Eine gefühlte Hunderstelsekunde später existiert im von mir benutzten Internet kein Verlagsangebot mehr. Das befreit mich von jeder Chance, die Machwerke bundesdeutscher Presseverleger zu sehen und dabei versehentlich irgendwo zu verlinken.

Denn ich finde, dass der energisch und würgmächtig wirkmächtig vorgetragene Wunsch dieser Leute nach einem Sonderstatus im Internet respektiert werden sollte. Die machen ja den »Qualitätsjournalismus«, und der wird schon für sich selbst sprechen. Ohne, dass es irgendeiner Verlinkung dorthin bedarf. Ein Feuer wirbt nun einmal für sich selbst, wenn es unter großem Leuchten alte Häuser verzehrt.

Ich wünsche mir in ganz besonderer Weise, dass große Suchmaschinen fortan ebenfalls auf die Verlinkung dieser Websites verzichten – zumindest so lange, bis die Betreiber dieser Websites eindeutig, öffentlich und rechtsverbindlich klargestellt haben, dass sie auf ihre aus dem »Leistungsschutzrecht« erwachsenen Rechte verzichten, indem sie eine allgemeine, vernünftige, unmissverständliche und für jeden Menschen kostenlos und ohne besondere Formalitäten zu verwendende Lizenz erteilen.

Vom Schicksal der Dinosaurier lernen, bedeutet: Verstehen, dass das Ansterben dem Aussterben voran geht.

Wer Bitterkeit in diesem Post findet, darf sie behalten. Diese Bitterkeit geht nicht von mir aus. Es ist die Bitterkeit, mit der ein aussterbendes Gewerbe versucht, die eigene Zerstörung durch eine teilweise Zerstörung der Kultur des Internet zu entschleunigen, und zwar ohne jede Rücksicht auf Verluste.

Wer die Datei blacklist-0.2.txt nicht gefunden hat: Die gibt es hier zum freien Download. Ich hoffe, sie ist einigermaßen vollständig. [Inzwischen ist es eine blacklist-0.3.txt, in die auch Zeit Online und Spiegel Online aufgenommen wurden. Weitere Ergänzungen sind noch möglich.]

Natürlich kann sie in dieser Form auch in der Hosts-Datei von Microsoft Windows verwendet werden, die Syntax der Einträge ist die gleiche. Vielleicht baut ja jemand einen kleinen, bequemen Windows-Installer für diese Datei. 😉

Es ist möglich, dass ich in Zukunft aktualisierte Formen dieser Datei pflege. Es ist aber auch möglich, dass mir das zu viel der Mühe für einen Haufen von Idioten ist.

Veröffentlicht unter Technisches | Verschlagwortet mit , , , | 12 Kommentare