Freitag, 14. Juni 2019

Rockrobo - root und gut?

Der Staubsauger ist in der Cloud und mein Typ Xiaomi Mi Robot Vacuum (rockrobo.vacuum.v1) wird auch noch von höchster Instanz (CCC) genau analysiert!
Was bedeutet es einen Staubsauger mit Root Zugriff zu haben?!
Markus hat gesagt: Es ist nur der ssh Zugriff - und irgendwann geht es vielleicht nicht mehr.
WLAN Zugang ändern und danach den Token neu auslesen - ist mit dem normalen Gerät ein Graus, aber mit ssh Zugang ganz einfach!?
Tobias hat mir mit seinem Beitrag die Hemmschwelle genommen - also los und Test!
Wie so oft: Meine Beschreibung wird auch irgendwann nicht mehr aktuell sein. Die Grundlage steht hier https://github.com/dgiese/dustcloud

Vorbereitung

Am Einfachsten erschien es mir, einen Raspberry Pi mit Wlan zu nehmen und mit einem neuen raspbian Image zu beginnen. Für spätere Arbeiten ist es sicher am einfachsten, man beschriftet die SD Card und hebt sie auf.
Der Linuxrechners und der Roboter müssen mit dem gleichen Netzwerksegment verbunden sein!
Der Roboter muss für den Flashvorgang in der Ladestation stehen!
Hinweis:
Für den einfachen "root Vorgang" (wenn der Roboter schon im Netz integriert und der Token bekannt ist) braucht man kein Wlan, dann geht auch jeder Linuxrechner im Lan. Will man einen neuen Roboter sofort rooten und ihn erst dann ins Netzwerk einbinden, braucht man Wlan (und Monitor und Tastatur). Man muss in dem Fall den Computer mit dem offenen Wlan des RockRobo verbinden.

Software bauen und flashen

Was hier eigentlich passiert ist keine Magie: die Originale Firmware wird entpackt/entschlüsselt, der ssh Zugang wird freigeschaltet und anschließend wird das Firmware Paket wieder zusammengebaut und auf die Sauger geflashed. Dazu wird das Tool mirobo und ein flasher Script verwendet, man muss also selbst nicht viel tun.
Den gesamten Vorgang schreib ich mal ein einem Block mit ein paar Kommentaren. Achtung: Ich starte aus dem Login des normalen User Pi, ohne sudo su!
# Software installieren
sudo apt-get update
sudo apt-get install ccrypt python3-pip dos2unix
sudo pip3 install python-miio
#ip Adresse und token ablegen um sich Tipparbeit zu sparen
ip="<ip adresse - kein name>"
token="<32 stelliger token>"
#Verbindung testen wenn man den Robo schon eingebunden hat
mirobo --ip $ip --token $token status
# ssh Key erzeugen, File bestätigen, Frage nach passphrase zweimal bestätigen (keine Passphrase!)
ssh-keygen -t rsa -b 4096 -C "RockRobo"
#Arbeitspfad erzeugen
mkdir dc && cd dc
#nur die drei Dateien laden und nicht das ganze Repository
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/imagebuilder.sh
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/flasher.py
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/adbd
# den Key ins Verzeichnis kopieren
cp ~/.ssh/id_rsa.pub .

#Firmware holen. Ab diesem Schritt muss man den Vorgang für jede zukünftige Firmware wiederholen 

#Bei mir ging dieser Link
wget https://cdn.awsde0.fds.api.mi-img.com/updpkg/v11_003468.fullos.pkg
#oder der
#wget https://dustbuilder.xvm.mit.edu/pkg/v1/3.3.9_003468/v11_003468.fullos.pkg
#Image erzeugen - der Vorgang läuft ein Weilchen...
sudo bash ./imagebuilder.sh -f v11_003468.fullos.pkg  -k id_rsa.pub -t Europe/Berlin
#Wenn alles Fehlerfrei lief kann man jetzt das Image flashen:
sudo python3 flasher.py -a $ip -t $token -f output/v11_003468.fullos.pkg
Jetzt wird der Staubsauger automatisch neu starten und meldet sich mit seiner Melodie zurück. Danach kann man sich per ssh einloggen. Das geht beim ersten Mal nur mit dem Account (und dem Key) der das Kommando ssh-keygen (siehe oben) ausgeführt hat!
ssh root@rockrobo
# Nach dem ersten Login kann man für die weitere Arbeit ein neues root passwort setzen.
passwd
Der Sauger ist weiterhin in der App und in FHEM verfügbar. Was man sich dank des Tools mirobo noch gönnen kann, ist eine deutsche Sprachdatei, das wäre aber wohl auch ohne root gegangen!?
wget https://dustbuilder.xvm.mit.edu/pkg/voice/de.pkg
mirobo --ip $ip --token $token de.pkg

Was geht jetzt mit root?

Wie schon gesagt: ssh Login.
Token auslesen.
printf $(cat /mnt/data/miio/device.token) | xxd -p
Wlan ohne reset ändern. Der Token bleibt dabei erhalten!
Der Inhalt der Datei wifi.conf entspricht ein bisschen dem Inhalt der Datei wpa_supplicant.conf. Quelle Ich arbeite gern mit nano, vi ist vorhanden und braucht nicht installiert zu werden.
apt-get update
apt-get install nano
nano /mnt/data/miio/wifi.conf
reboot
Neue Firmware darf man nur noch nach dieser Methode einspielen! Keine Updates mit einer App machen!
Man kann zur Sicherheit die Updates erstmal verhindern.
mv /usr/bin/ccrypt /usr/bin/ccrypt_
touch /usr/bin/ccrypt
chmod +x /usr/bin/ccrypt
Die Palette der weiteren Möglichkeiten ist groß: Den Rockrobo aus der Cloud aussperren, Software installieren, die Karten sichern ...

Kleines Zwischenspiel

Mir ist aus keiner der Beschreibungen im Internet so richtig klar geworden wie es "weitergeht"!
Was ist mit neuer Firmware? Es gibt eine Liste getesteter Firmware, aber welche ist gut, aktuell, neu?
Die Mi Home App hat mir ein Update angeboten, die Flole App hat andere Updates angeboten, was bedeutet denn fullos.pkg oder app.pkg? Das Update der Mi Home App (v11_003476.app.pkg) war nur 29 MB groß. Die Aufbereitung mit dem imagebuilder schlug fehl. Die Versionsnummer hatte einen "Sprung" 3.5.0 statt 3.3.9 - was soll man tun?
Ich war so mutig, habe die Updates wieder aktiviert und versucht: Damit war mein Root Zugang weg. Und nun? Es bleibt nur Factory Reset!
Es gibt drei Arten von Reset (neben einfach aus und wieder einschalten)
  1. WiFi Reset: beide Tasten auf der Oberseite (Home und Ein/Aus) drücken und Nachricht abwarten. Danach ist WiFi gelöscht und man kann den Sauger mit der Mi Home App neu anlernen.
  2. Reset: Taster unter dem Deckel mit Stift o.ä. drücken. Danach wird das System neu gestartet und WiFi ist gelöscht.
  3. Factory Reset: Home drücken und halten, Reset Taster mit Stift/Büroklammer drücken, Home weiterhin halten bis die Nachricht für Factory Reset ertönt. Danach ist softwaretechnisch der Auslieferungszustand erreicht. Die Logs über Verbrauch usw. scheinen erhalten zu bleiben.
Diesen Tipp habe ich gefunden aber nicht getestet: Man kann auch das Factory Image analysieren und rooten.

Rooten nach dem Auspacken/Factory Reset

Das ist eigentlich zu empfehlen, damit kommt man unkompliziert an den Token und kann das Wlan leicht verwalten. Das Anlernen an die App (falls man das will) macht man erst nach dem rooten.
Dafür braucht man jetzt einen Linux Rechner, den man mit dem offenen Wlan des Rockrobo verbinden kann. Und irgendwo stand: man darf kein zweites Netzwerkinterface haben. Also hab ich einfach Monitor und Tastatur an meinen schon vorbereiteten Raspberry Zero angesteckt.

Achtung! Der Rockrobo hat im AP Mode nicht all zuviel Leistung! Zum Flashen muss der Linux Rechner und der Roboter im gleichen Raum im Umkreis weniger Meter und in der Ladestation stehen!

Ich bin gewohnt Wlanverbindungen über die Datei /etc/wpa_supplicant/wpa_supplicant.conf einzurichten. Nach kurzem Test war klar: Geht universell und auch ohne WPA. Man muss die exakte ssid mit dem Befehl sudo iwlist scan scannen und dann die Datei so abändern.
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="rockrobo-vacuum-v1_miapF0C8"
        key_mgmt=NONE
}
Ich musste den Raspberry neu starten um die Verbindung mit dem offenen Wlan herzustellen.
In diesem Stadium gibt der Rockrobo seinen Token einfach so her. Der Befehl zum Test:
mirobo discover --handshake true
Auch der Flash Befehl geht etwas "einfacher":
sudo python3 flasher.py -f output/v11_003468.fullos.pkg
Nach dem Neustart und erfolgreichem ssh Login kann man entweder den Rockrobo direkt mit dem Wlan verbinden oder falls man die Mi Home App nutzen will, den Rockrobo mit der App einrichten.

Ein paar Zusatzinfos 

Ich habe auch mal probiert den Token selbst zu setzen, weil man vielleicht zu faul ist den in FHEM zu ändern. Dafür muss man ihn ins interne Format wandeln.
echo "44446e74695a4445713547644a79444d" |xxd -r -p
Man kann auch das interne root Passwort auslesen. Ich habe die Richtigkeit von diesem Code nicht überprüft.
perl -e 'print(join("", (map { chr(ord($_) ^ 0x37) } split(//, $ARGV[0]))), "\n");' `cat /mnt/default/vinda`

Für die Zukunft

Keine Updates über irgend eine App!
Auf der Webseite schauen welche Firmware getestet ist!

Mittwoch, 8. Mai 2019

Worx Landroid m500

Ich habe mir nach kurzer Überlegung und Klärung der Unterstützung in FHEM einen Mähroboter zugelegt. Nachdem ich die Installation und Einbindung in FHEM geschafft habe, will ich die mal hier festhalten. Als Grundlage gibt es einen kurzen Wikibeitrag. Dort sind zumindest mal die wichtigsten Links abgelegt. Ich habe die Installation etwas nach meinem Geschmack modifiziert, die Grundlage bildet aber diese Anleitung https://github.com/axelmohnen/fhem-landroid-s
Man sollte sich immer erst auf dieser Seite davon überzeugen, ob es Änderungen gibt!

Die Voraussetzungen:
  • Cloudzugang eingerichtet und Mäher registriert. App funktioniert!
  • Installation Node.js, dieses Setup habe ich schon in einem extra Artikel beschrieben.

Setup Schritt für Schritt

Man sollte die Zeilen Schritt für Schritt ausführen und nicht einfach den Block als Script übernehmen.
sudo apt-get install libjson-pp-perl
sudo mkdir -p /opt/landroid/fhem-landroid-s
sudo chown -R pi /opt/landroid
sudo chmod -R 777 /opt/landroid
cd /opt/landroid/fhem-landroid-s
# Ich verzichte auf git und lade die beiden Datei einfach herunter
wget -O LandroidConf.json https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/LandroidConf.json
wget -O LandroidSrv.js https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/LandroidSrv.js
# bei der Installation gibt es ein paar Warnmeldungen
sudo npm install iobroker.landroid-s
sudo npm install pm2 -g
# Ich korrigiere einen aktuellen kleinen Schönheitsfehler fürs Logging
sed -i -e 's/self.mqtt)/self.mqtt_endpoint)/' node_modules/iobroker.landroid-s/lib/mqttCloud.js
# Jetzt den Cloudzugang eintragen und mit ctrl+o speichern und mit ctrl+x schließen
nano LandroidConf.json
Wenn man alles richtig gemacht hat, kann man jetzt schon mal auf zwei Arten testen:
node /opt/landroid/fhem-landroid-s/LandroidSrv.js mower1
# im Browser kann man sich den aktuellen Datensatz anzeigen lassen
http://ip-adresse-landroidsrv:8001/getMessage
Die Logausgaben sind selbsterklärend. Mit ctrl+c kann man den Testlauf abbrechen.

Automatischer Start

Auch mit der Node Prozess Steuerung kann man die Funktion testen
pm2 start /opt/landroid/fhem-landroid-s/LandroidSrv.js -f -- mower1
pm2 monit                           # zeigt Status
pm2 list                            # zeigt Prozesse
pm2 logs LandroidSrv [--lines 1000] # zeigt das Log
Sieht alles gut aus, kann man jetzt den Autostart aktivieren.
Diese Einrichtung war mir zunächst etwas schleierhaft. Aber - pm2 redet mit einem, und man muss genau lesen was er sagt.
Durch Eingabe von pm2 startup erhält man nach einer Analyse des Systems eine Zeile die man selbst noch einmal kopieren und in der Eingabezeile ausführen muss.
pm2 startup
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
Hat man die Zeile ausgeführt muss man die pm2 Konfiguration noch speichern.
pm2 save
Nach einem Neustart des Servers kann man sich davon überzeugen ob alles geklappt hat.
Achtung!
Ich habe mich mehrfach aus der AWS Cloud ausgesperrt! Offenbar ist es mir unbewusst gelungen, den LandroidSrv mehrfach zu starten und dies auch in pm2 zu verankern. Hast Du nicht gesehen, lief er 1x unter User pi und 2x unter User root. Wie ich das geschafft habe und was da genau abgeht weiß ich noch nicht. Mit ps
ps -aux|grep pm2
kann man schauen wie oft der Prozess läuft. Weiter unten habe ich geschrieben wie man alles wieder löschen kann.
pm2 legt für den angemeldeten User jeweils Prozesse an! Also nicht einmal als sudo und einmal als pi einrichten (hatte ich offenbar gemacht).

Setup FHEM

Zunächst brauchen wir das (derzeit nicht offizielle) Modul. Das laden wir direkt von GitHub an Ort und Stelle. Das notwendige Perl Modul haben wir oben als ersten Schritt schon installiert. Der Code ist entweder Zeilenweise für die FHEM Kommandozeile oder komplett für die Raw Definition.
"wget -nv -O FHEM/74_LANDROID.pm https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/74_LANDROID.pm"
reload 74_LANDROID.pm
define robbi LANDROID localhost
attr robbi event-on-change-reading .*
define FileLog_robbi FileLog ./log/robbi-%Y.log robbi
attr FileLog_robbi logtype text
Die ersten Reading sollten nach 180 sec erscheinen.

Noch Dies und Das

Zunächst die Installation aus der Readme vom GitHub in kurzer Zusammenfassung
sudo apt-get install git
cd /opt
sudo mkdir landroid
sudo chown pi landroid
sudo chmod 777 landroid
cd landroid
git clone https://github.com/axelmohnen/fhem-landroid-s.git
cd fhem-landroid-s
sudo npm install iobroker.landroid-s
# bei der Installation gibt es ein paar Warnungen und eine
# npm WARN saveError ENOENT: no such file or directory, open '/opt/landroid/fhem-landroid-s/package.json'
# npm notice created a lockfile as package-lock.json. You should commit this file.
# Jetzt account eintragen
nano LandroidConf.json
#Teststart
node LandroidSrv.js mower1

Fehler beim Start

Wenn man sich im Argument vertippt hat (mover statt mower) kommt dieser Fehler
/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:24
    this.email = adapter.config.email;
                                ^

TypeError: Cannot read property 'email' of undefined
    at new mqttCloud (/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:24:33)
    at main (/opt/landroid/fhem-landroid-s/LandroidSrv.js:420:14)
    at Object. (/opt/landroid/fhem-landroid-s/LandroidSrv.js:458:3)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
Ich hatte einen hartnäckigen Fehler, weil mich die Amazon Cloud offenbar gesperrt hatte (ich hatte durch einen Fehler eine Art Attacke gefahren). Abhilfe war: DSL neu verbinden.
undefined:1
<html>
^

SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at IncomingMessage.<anonymous> (/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:275:21)
    at IncomingMessage.emit (events.js:194:15)
    at endReadableNT (_stream_readable.js:1125:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

Alles löschen

Der iobroker.landroid-s wird unterhalb des aktuellen Pfades bei der Installation unter node_modules abgelegt.
Wenn man alles wieder loswerden will:
pm2 unstartup
pm2 stop /opt/landroid/fhem-landroid-s/LandroidSrv.js
pm2 delete /opt/landroid/fhem-landroid-s/LandroidSrv.js
sudo npm uninstall iobroker.landroid-s
cd /opt
sudo rm -R landroid/

Code Block


Dienstag, 7. Mai 2019

Windows von FHEM über ssh steuern

Windows OpenSSH Server installieren

Als ersten Schritt sollte man zunächst unabhängig von der Windows Version prüfen ob ein entsprechender Dienst schon läuft oder existiert:
Get-Service -Name *ssh*

Windows 10 + Server 2019

In den aktuellen Windows Versionen ist der OpenSSH Server enthalten und kann einfach installiert werden.
Get-WindowsCapability -Online | where name -match 'OpenSSH.Server'|Add-WindowsCapability -Online
Get-Service -Name sshd | Set-Service -StartupType Automatic
Get-Service -Name sshd | Start-Service

Windows Server 2016, 2012 R2 und 2012

In früheren Windows Versionen kann der OpenSSH Server nur über ein extra download/Setup installiert werden.
Als Voraussetzung für die Installation muss die Ausführung von Powershellscripten erlaubt sein.
Set-Executionpolicy Remotesigned
Ich habe für die Installation ein komplettes Script auf GitHub  zur Verfügung gestellt.
Man kann es einfach herunterladen und starten.
invoke-webrequest https://raw.githubusercontent.com/heinz-otto/Powershell/master/InstallLatestSshd64.ps1 -OutFile InstallLatestSshd64.ps1
.\InstallLatestSshd64.ps1
Das Script überprüft die Windows Server Version und installiert ein fehlendes
Windows Management Framework 5.1 (dann ist zwischendurch ein Reboot erforderlich). Es wird die aktuellste sshd Version heruntergeladen und die Anmeldung für die Administratoren Gruppe freigeschaltet.

Anmeldung am Windows OpenSSH Server

Man kann sich wie gewohnt von jedem System (Windows 10 Version 1803 hat den ssh Client aktiv) mit ssh user@host am SSH Server anmelden!
Der ssh Server akzeptiert nur den "Kurznamen". Windows kürzt den Anmeldenamen ein (z.B. bei einem Onlinekonto).
Man kann den Namen leicht in der Powershell Konsole ermitteln:
whoami

SSH Zugang mit Public Key einrichten

Bitte den Hinweis am Ende des Artikels für die Gruppe der Administratoren beachten!
Bitte alle Schritte (Befehlszeilen) einzeln kopieren und ausführen!

Problem: Bei Windows als SSH Server versagt leider das Tool ssh-copy-id. Der folgende Dreizeiler ist nicht perfekt aber funktioniert.
Voraussetzung: Benutzer hat schon einen RSA Key.

Linux Shell
ziel=user@host
scp ~/.ssh/id_rsa.pub $ziel:key.tmp
ssh $ziel "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
Windows CMD
set ziel=user@host
scp %userprofile%\.ssh\id_rsa.pub %ziel%:key.tmp
ssh %ziel% "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
Hinweis: Die Befehle nach ssh werden in der CMD von Windows abgearbeitet! "&" dient hier als Befehlstrenner. Mir ist es bisher nicht gelungen nur mit ssh und ohne scp zu arbeiten.

Ersteinrichtung
Alle Schritte in Kurzform für den Public Key Zugang für den User fhem zu einem Windows SSH-Remotesystem, in der Linux Shell auf FHEM Server:
sudo cp /etc/passwd /etc/passwd.sav
sudo  sed -i -e 's/fhem:.*/fhem:x:999:20::\/opt\/fhem:\/bin\/bash/' /etc/passwd
sudo passwd fhem             # Passwort vergeben und bestätigen
su fhem                      # Als fhem einloggen, es startet eine neue session!
ssh-keygen -t rsa            # optional falls noch kein Key existiert. Speichert automatisch in /opt/fhem/. Keine passphrase vergeben! 2x enter 
ziel=user@host               # Benutzer und Host einmal eintragen
scp ~/.ssh/id_rsa.pub $ziel:key.tmp
ssh $ziel "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
ssh $ziel                    # nur zum Test - es startet eine neue session!
exit                         # aus der ssh Test session vom Remotehost!
exit                         # aus der Anmeldung von fhem!  
sudo cp /etc/passwd.sav /etc/passwd
Ein ganz schneller Funktionstest für die FHEM Kommandozeile.
{qx(ssh user\@host dir)}
Hinweis: Innerhalb von Perl muss das @ schützen!

Powershellscript von FHEM aus starten

Bei der Ausführung von Befehlen vom Linux System aus muss man beachten, dass der Backslash verdoppelt (geschützt) werden muss. Ansonsten kann man wie gewohnt Befehle absetzen und sogar Powershell Scripts mit Argumenten ausführen.
"ssh user@host 'powershell C:\\Tools\\Scripts\\TestPsFhem.ps1' 'http://host:8083' 'DummyName'"
Innerhalb von Powershell kann man auch mit einem Powershellscript über HTTP auf FHEM zugreifen.
Powershellbeispiel:
Fragt einen Dienst ab und schreibt Status und Displayname nach FHEM zurück in einen Dummy
<#
.SYNOPSIS
    This Script is for testing the FHEM Client for HTTP
.DESCRIPTION
    Give FHEM Server url and Dummy 
.NOTES
    Will give a State and Displayname of Service back
#>
#region Params
param(
    [Parameter(Mandatory=$true,Position=0,HelpMessage="-first 'Portnumber or URL'")]
    [String]$first,
    [Parameter(ValueFromPipeline=$true,ValueFromRemainingArguments=$true)]
    [String[]]$sec
)
#endregion 
$serv="wuauserv"

if (!(Test-Path .\fhemcl.ps1)) {
    Write-Output "fhemcl.ps1 fehlt"
    invoke-webrequest "https://raw.githubusercontent.com/heinz-otto/fhemcl/master/fhemcl.ps1" -OutFile "fhemcl.ps1"
}

$state=get-service $serv
.\fhemcl.ps1 $first "set $sec $($state.status)"
.\fhemcl.ps1 $first "setreading $sec Displayname $($state.DisplayName)"


Eigenheiten Windows Server 2012?

Symptom:
Ein Mitglied der Gruppe administrators kann offenbar keine Anmeldung mit Public Key machen. Obwohl alles eingerichtet ist, wird das Passwort abgefragt. Ich habe das nur in der Version 2012 und nicht bei 2012 R2 und 2016 beobachtet.
Lösung:
Ich habe mir die Sache näher angeschaut und dabei festgestellt, ich habe bei einigen Installationen Unterschiede in der aktiven sshd Konfigurationsdatei C:\ProgramData\ssh\sshd_config gefunden.
Kommentiert man dort am Ende der Datei den folgenden Eintrag mit einem # aus,
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
funktioniert auch die Anmeldung für Mitglieder der Administratoren. Der Dienst ssd (OpenSSH SSH Server) muss dafür neu gestartet werden.
Hintergrund:
Der sshd vergleicht dabei die Klarnamen der Gruppenbezeichnung. Ich installiere gern für den Server EN Systeme und gebe Ihnen eine DE mui.
Ein 2012 EN System mit DE mui hat administrators - > match!
Alle späteren EN Systeme (2012 R2, 2016) mit DE mui haben Administratoren -> kein match!

Der folgende Code kommentiert die verantwortlichen Zeilen in der config aus. In meinem Setupscript für die älteren Serversysteme ist dieser Code bereits enthalten.
# Patch sshd config to allow administrators Group public Key logon
$Quelle="${Env:ProgramData}\ssh\sshd_config"
write-output "patch the sshd config on $Quelle"
Stop-Service -Name sshd
$Inhalt = Get-Content $Quelle
#search 2 lines contains administrators and insert commment sign
$Inhalt|foreach {if ($_ -match "administrators") {$Inhalt[$_.readcount-1]=$_.Insert(0,"#")}}
set-Content $Quelle $Inhalt
Start-Service -Name sshd

Den OpenSSH Server wieder loswerden

Stop-Service -Name sshd 
pushd
cd "${Env:ProgramFiles}\OpenSSH-Win64\" 
.\uninstall-sshd.ps1
popd
rm -recurse "${Env:ProgramFiles}\OpenSSH-Win64"
rm -recurse "${Env:ProgramData}\ssh"
Remove-NetFirewallRule -Name sshd

Zum Nachlesen

Ziel des Artikels war es, kurz und knapp alle Schritte zusammenzufassen.
Ausführlicher kann man in folgenden Artikeln nachlesen:
https://heinz-otto.blogspot.com/2018/06/windows-hat-jetzt-ssh.html
https://heinz-otto.blogspot.com/2017/01/per-ssh-remote-befehle-direkt-ausfuhren.html
https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration



Montag, 6. Mai 2019

Setup Raspberry Pi 2019

Mal wieder ist ein Jahr um und ich habe ein bisschen dazu gelernt. Ich stelle jetzt meine Setup Scripts über GitHub zur Verfügung, das macht es leicht sie einfach beim Setup zu laden.
Am grundlegenden Setup hat sich nicht soviel geändert, deswegen verzichte ich hier auf Detailbeschreibungen, soweit die vom vorigen Jahr noch gelten.

Mein Setup basiert auf einem aktuellem raspbian Lite Image, welches von raspberrypi.org herunter geladen wird und mit einem Imagetool (Windows z.B. win32DiskImager) auf die SD Card geschrieben wird. Für die Headless-Installation braucht man den ssh Zugang und darf die Datei ssh im Bootlaufwerk nicht vergessen! Vor dem Kopieren den Laufwerksbuchstaben richtig setzen (meine Codeboxen sind editierbar) ctrl+a um alles zu kopieren, Windows+r um die Ausführen-Box zu erhalten und die Zeile dort "einwerfen".
cmd /c echo " " >e:\ssh

Beim Setup braucht man erweiterte Rechte, deshalb alles im Context "root" - sudo su ausführen! Man kann die Scripts entweder mit chmod +x ausführbar machen oder einfach mit bash Scriptname starten. Bitte beachten:
Alle meine Scripts sind für "einmaligen" Gebrauch bestimmt! Ich habe praktisch keine Fehlerbehandlung für wiederholte Ausführung und Bereinigung drin. Sollte also während der Installation etwas schief gehen, kann man völlig neu beginnen oder muss die Installation Schritt für Schritt manuell ausführen!

Die Basis

Die Grundeinstellung: Zeitzone Berlin, Land und Locale DE, Hostname. Das müsste eigentlich noch um die Abfrage des Passwortes für Pi ergänzt werden.
Das Setup Script startet aber mit einem Upgrade des aktuellen Raspbian Standes, je nach nach aktuellen Zeitpunkt "zwischen den Images" kann das aktuelle Image schon ein paar Monate alt sein und könnte offene Lücken haben.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupBasic.sh
Jetzt hat man ein aktuelles raspbian, das restliche Setup ist Anwendungsspezifisch.

Für Pi mit Bluetooth Modul

Als nächstes kann man für Zusatzmodule auf der GPIO-UART Schnittstelle beim Pi3 und P3+ diese Schnittstelle aktivieren.
Bei den Modellen B, B+, B2 braucht man diesen Schritt nicht!
Nach diesem Script wäre ein Neustart fällig, aber nicht an dieser Stelle notwendig und deshalb nicht integriert. Den reboot kann man jederzeit später einbauen.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupUartPi3.sh

Samba Server

Für die Sprachausgabe brauche ich einen SMB Server. Das folgende Script installiert den Dienst und ein SMB Share, welches ohne Anmeldung frei beschreibbar ist!
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupSamba.sh

FHEM

Auch das Script für die grundlegende FHEM Installation habe ich angepasst. Ich verwende jetzt zwei Textdateien in denen meine aktuell zusätzlich verwendeten deb Pakete und Perl Module (cpan) enthalten sind. Wer das lokal anpassen möchte erstellt einfach im aktuellen Pfad (/home/pi) beide Dateien mit entsprechendem Inhalt. Die vorhanden Dateien werden vom Script genutzt und nicht überschrieben.
Das Script arbeitet folgende Schritt ab:

  • Vorbereitung FHEM Setup gemäß https://debian.fhem.de/
  • Hole Textdateien mit zusätzlichen deb Paketen und Perl Modulen
    • und Installiere ...
  • Installation FHEM
  • Basiskonfiguration FHEM 

wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupFhem.sh
Nach dem Download ist es sicher sinnvoll, gerade die Basiskonfiguration von FHEM noch anzupassen und zu erweitern. Z.B. die Ortsabhängigen Koordinaten attr global l...
Ein automatisches Save am Schluss der Konfiguration ist in meinem Script nicht drin!

Backup

Wer möchte kümmert sich auch jetzt sofort ums Backup. Ich hatte dazu schon etwas geschrieben. Das Script muss nach dem download angepasst werden.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/configBackupFhem2Cifs.sh

Nodejs

Einige Applikationen erfordern die Anbindung mit Node Server. Die Installation habe ich hier beschrieben, ein Script dazu muss ich mir mal überlegen.
todo

Update

Ein vorhandenes System aktuell halten, wie macht man es richtig? So einfach wie unter Windows ist es leider nicht.
Hier gibt es einen Ausgangspunkt für  mein ToDo
https://forum.fhem.de/index.php/topic,101232.0.html#lastPost

Freitag, 3. Mai 2019

Installation Node.js

Ein neues Gerät ist im Haus, und die Anbindung an FHEM erfordert Node.js.
Als asynchrone, Event-basierte Laufzeitumgebung wurde Node speziell für die Entwicklung von skalierbaren Netzwerkanwendungen entworfen.
Das js steht für Javascript.
Ich habe immer das Gefühl, die meisten Anleitungen sind in einer eigenen, mir nur sehr schwer verständlichen Sprache geschrieben. Manche treiben meinen Puls in die Höhe und es tritt Angstschweiß auf die Stirn.
Deswegen versuche ich es mal für meine Umgebung, denn komischerweise ist auch die Originalseite so geschrieben, dass man sich tar Pakete aussucht, herunterlädt und irgendwie entpackt. Aber ganz versteckt findet man auch die Variante für Debian.
Auf der Nodejs.org Seite steht aktuell, dass die Version 10.15.3 derzeit die Active LTS Version ist.

Bitte vor der Installation die aktuelle Version nachschauen, oder die von der Anwendung geforderter Version installieren! Meist steht dort aber neuer als x.x.x

Da es entspannter ist und die Installation höhere Rechte braucht, füge ich den kopierten Zeilen von der oben verlinkten Seite noch eine hinzu.
sudo su
# Using Debian, as root
curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install -y nodejs
Von der Webseite wird quasi ein Script heruntergeladen und der bash als Standardinput übergeben. Anschließend ist nodejs im Paketmanager verfügbar.
Mit diesen Befehlen kann man die installierte Version abfragen.
node -v
npm -v
npm ist für die Installation von node Paketen zuständig und wird für die weitere Installation benötigt.
Damit ist die Installation der offiziellen Nodejs Softwareversion abgeschlossen. Und das System ist bereit für die eigentliche Installation der Anwendungssoftware.

Dienstag, 23. April 2019

Backup wenn der Server kommt

FHEM sichert ziemlich viel selbstständig, allerdings lokal innerhalb der Ordnerstruktur von FHEM. Geht beim Raspberry mal die SD Card kaputt, sollte man das Backup auf einem anderen System gesichert haben. Da bietet sich die NAS, der Windows Server oder was auch immer im lokalen Netzwerk an.
Ich möchte zeigen, wie man bestimmte Ordner von FHEM auf ein temporäres Netzlaufwerk sichert und wie man diese Sicherung triggern kann.
Meine Codezeilen bauen aufeinander auf und ergeben in der Summe eine Art Setup Script. Damit ist das relativ zügig eingerichtet und auf mehreren Computer installiert. Die Einrichtung erfordert höhere Rechte, also bitte im Context sudo su ausführen!

Laufwerk verbinden

Auf dem Server1 existiert eine SMB Freigabe "Sicherung". In einem Unterverzeichnis fhem (muss noch nicht existieren) wird zukünftig die Sicherung des FHEM Server abgelegt.

# Konfiguration der Datei, Server, Ordnernamen und des Benutzerkontos
fcred='smbcredentials'
share='//Server1/Sicherung'
mdir=/media/Sicherung
# Benutzerkonto ablegen
echo 'username=UserName' > /usr/.$fcred
echo 'password=Userpassword' >> /usr/.$fcred
# fstab Eintrag anhängen
echo "$share $mdir cifs noauto,users,credentials=/usr/.$fcred 0 0" >> /etc/fstab
# Ordner erzeugen, Verbindung testen
mkdir $mdir
mount $mdir
mkdir ${mdir}/fhem
umount $mdir
Die letzte Sequenz testet gleichzeitig ob die Verbindung zum Server funktioniert und die Rechte zum Schreiben vorhanden sind. Ich hatte hier schon mal ein paar Details erklärt.

Das backup Script

Damit alles in einem "Rutsch" ohne großes Hin und her funktioniert, habe ich das Script zur Sicherung als Here Doc abgelegt. Dabei wird die Konfigurationsvariable $mdir aus dem ersten Schritt verwendet!
cat <<EOF > /opt/fhem/backupFhem.sh
qpath="/opt/fhem"
dpath=$mdir
LOG=backupFhem.log
if [ -d "log" ];then LOG="log/\$LOG";fi
# check if fhemcl exists
file=fhemcl.sh
{
date
if [ ! -e \$file ]
then
    echo "\$file is missing"
    wget https://raw.githubusercontent.com/heinz-otto/fhemcl/master/\$file
    chmod +x \$file
fi
# mount, sync 
mount "\$dpath"
bash fhemcl.sh 8083 "set BackupFhem gestartet"
if rsync -rut \${qpath}/backup \${qpath}/restoreDir \${dpath}/fhem/\$(hostname)
then
   bash fhemcl.sh 8083 "set BackupFhem gesichert"
else
   bash fhemcl.sh 8083 "set BackupFhem ERROR"
fi
umount "\$dpath"
} >> \$LOG 2>&1
EOF
Gesichert werden die beiden Pfade backup und restoreDir. Der gesamte Ablauf wird im FHEM gesteuert und geloggt. Zur Orientierung wird ein Startzeiteintrag ins Log geschrieben. Das Serverlaufwerk wird bewusst nur temporär gemountet.
Falls Fehler im Script auftreten wird eine Logdatei geschrieben. Der dazu notwendige HTTP Client wird, falls nicht vorhanden, von GitHub nachgeladen.

Steuerung über FHEM

In FHEM sind dazu zunächst mal ein Dummy und ein FileLog Device notwendig. Mit dem "fakelog" wird das Logfile vom Script zur Anzeige gebracht.
Man kann diese Codezeilen mit der Raw Definition oder auch mit dem FHEM HTTP Client direkt per Script in FHEM eingeben.
define BackupFhem dummy
attr BackupFhem room backup

define backupFhemlog FileLog ./log/backupFhem.log fakelog
attr backupFhemlog room backup
Für den automatischen Start gibt es mehrere Varianten/Ideen:

  • der SMB Server meldet an FHEM über ein Powershell Script das er gestartet ist.
  • der Start des Server wird mit einem Presence Device überwacht
    • mit einem Perl Script ermitteln das Port 445 / SMB aktiv ist
    • mit lan-ping  
In jedem Fall übernimmt z.B. ein DOIF den Start des Scripts backupFhem.sh.
define backupCopy DOIF ([Server1] eq "present") ("bash backupFhem.sh")
attr backupCopy room backup
Die Reaktion des Servers auf ein LAN Ping, stellt nicht zuverlässig sicher, dass das SMB Share schon erreichbar ist. In dem Fall kann man mit einem wait eine Wartepause vor der Ausführung einlegen.
attr backupCopy wait 120

Die Konfiguration für FHEM gibt es noch in einem Script, falls der FHEM HTTP Client im lokalen Pfad nicht vorhanden ist, wird er herunter geladen.
#file=fhemcl.sh
if [ ! -e $file ]
then
    echo "$file is missing"
    wget https://raw.githubusercontent.com/heinz-otto/fhemcl/master/$file
    chmod +x $file
fi
# ab hier wird der Code im (lokalen) FHEM Server erzeugt
cat <<EOF | bash fhemcl.sh 8083
define BackupFhem dummy
attr BackupFhem room backup
define backupFhemlog FileLog ./log/backupFhem.log fakelog
attr backupFhemlog room backup
define backupCopy DOIF ([Server1] eq "present") ("bash backupFhem.sh")
attr backupCopy room backup
attr backupCopy wait 120
EOF

Monitor für TCP Port

Mit dieser Perl Sub in der 99_myUtils.pm kann man gezielt einen bestimmten Port überwachen.
Achtung! Diese Sub wirkt blockierend.
sub ServiceMonitor($$)
# Usage: ServiceMonitor("Hostname","Portnummer")
# in Presence: function {ServiceMonitor("Hostname","Portnummer")}
{
    use Net::Ping;
    my ($host, $port)    = @_;
    my $status;
    
    # Create a new ping object
    my $p = Net::Ping->new("syn");
    $p->port_number($port);
    $p->ping($host,10);
    
    # perform the ping
    if ( $p->ack ) {
  $status = 1;
    }
    else{
     $status = 0;
    }
    
    # close our ping handle
    $p->close();
    return $status;
    
}

Alternativen zum SMB Server

Natürlich kann anstatt des SMB Servers auch ein anderes Server Laufwerk eingebunden werden. Es könnte z.B. auch ein Cloud Speicher über WebDav sein. Allerdings sollte man sich dazu überlegen, die Dateien zusätzlich zu verschlüsseln.

Zum Schluss

Hier noch ein komplettes Muster Script zum download.
wget -O https://raw.githubusercontent.com/heinz-otto/raspberry/master/configBackupFhem2Cifs.sh


Dienstag, 19. März 2019

Precence und OpenWrt - der 3. Versuch

Am Wochenende habe ich meinen OpenWrt Router WRT1900ACS mit neuer Firmware versorgt und dabei fiel dann relativ schnell auf, da war doch noch was...
Die beiden Varianten um festzustellen, ob bestimmte Geräte im Wlan angemeldet sind, die ich im Juni bzw. August 2018 schon mal getestet habe, haben einen ganz entscheidenden Nachteil: Sie überleben das Firmware Update nicht!
Ich hatte die Variante aus August zwar als Provisorium ohne Probleme laufen, aber so richtig zufrieden war ich damit sowieso nicht.
Der ssh Zugang zum OpenWrt Router überlebt das Firmware Update!
Deswegen eine neue Version. Ich beschreibe der Vollständigkeit halber an dieser Stelle auch noch einmal in Kurzfassung die Einrichtung des passwortlosen ssh Zuganges von fhem zum OpenWrt Router. Die Langfassung gab es ja schon in 2017.

Vorbemerkung

Das Tool ssh-copy-id kann nicht mit den speziellen Pfaden von dropbear (ssh OpenWrt) umgehen, deshalb kommt mein "Einzeiler" aus dem Artikel zum Einsatz.
Ich weiß, dass man prinzipiell die ssh Keys auch vom aktiven User auf den User fhem kopieren kann. Bei sicherheitsrelevanten Themen bin ich lieber für "ordentliches" und vielleicht etwas aufwendigeres Vorgehen.

ssh Zugang mit Public Key einrichten

Achtung: In zwei Zeilen muss am Anfang der username und der hostname eingetragen werden. Meine Codeboxen sind editierbar, man kann es hier direkt tun und die Zeile anschließend kopieren. Der "Einzeiler" zum ssh Key kopieren ist etwas lang!
sudo cp /etc/passwd /etc/passwd.sav
sudo sed -i -e 's/fhem:.*/fhem:x:999:20::\/opt\/fhem:\/bin\/bash/' /etc/passwd
sudo passwd fhem             # Passwort vergeben und bestätigen
su fhem                      # Als fhem einloggen, es startet eine neue session!
# prüfen ob fhem schon einen ssh Key hat, wenn nicht einen erzeugen
ls -lha /opt/fhem/.ssh/id_rsa        # ssh-keygen -t rsa 
# Remote User und Hostname/IP eintragen!
cat /opt/fhem/.ssh/id_rsa.pub | ssh <user>@<remote-system> "p='/etc/dropbear';akey=\$p'/authorized_keys'; pub=\$(cat ); umask 077; test -d \$p || mkdir \$p; test -f \$akey || echo \$pub >\$akey; grep -q \"\$(echo \$pub)\" \$akey || echo \$pub >>\$akey"
ssh <user>@<remote-system>   # Einmal testen - es startet eine neue session!
exit                         # aus der ssh Test session vom Remotehost!
exit                         # aus der Anmeldung von fhem!  
sudo cp /etc/passwd.sav /etc/passwd

FHEM

Die Einrichtung in FHEM besteht aus einem Script und einem Presence Device.

Script

Meine Script liegen jetzt alle auch auf GitHub, wer das aktuelle Script einfach laden will kann das wie hier gezeigt tun, fhem braucht selbst nur Lese Rechte. Im Script muss normal nichts konfiguriert werden.
Dieser Befehl lädt das Script ohne Umwege ins FHEM Verzeichnis:
sudo wget -O /opt/fhem/GetMacPresence.sh https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/GetMacPresence.sh
Ich habe keinen anderen Benutzer in OpenWrt angelegt, sollte man aber vielleicht tun.
Das Script liefert lediglich, wie vom Modul gefordert, 0 oder 1 zurück, MAC Adresse und Routername werden als Parameter übergeben.
MAC=$1
host=$2
user="root"
ssh $user@$host '
    if (
      for m in $(
                 for w in $(iwinfo |grep -oE "wlan\d-\d|wlan\d")
                 do
                   iwinfo $w assoclist | grep -o -E "([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}"
                 done
                )
      do
        [ "$m" = '"$MAC"' ] && exit 0
      done
      exit 1
    )
  then
    echo 1
  else
    echo 0
  fi
'

Presence Device

Das Beispiel zeigt die einfachste Verwendung, neben der zu suchenden MAC Adresse wird noch der Name des OpenWrt Routers angegeben.
define WL_Dev1 PRESENCE shellscript "bash GetHostPresent.sh 11:22:33:AA:BB:CC wrt1900"

Erfahrung

Ein Problem tritt relativ schnell zu Tage: Man kann offenbar dieses Script nicht mehrfach starten, dann führt irgendeine Komponente zum Abbruch.