Files
duffyduckandClaude Opus 5 24070cba4e Assistent mit Menuefuehrung, dazu zwei Haertungen
kerio_tui.py fuehrt durch Umbenennung und Uebernahme, ohne dass man
Parameter kennen muss: Benutzer und Domains kommen zur Auswahl, verwaiste
Mailbox-Verzeichnisse findet der Assistent selbst, und vor dem Ausfuehren
zeigt er den gleichwertigen Kommandozeilenaufruf. Nur curses aus der
Standardbibliothek, keine neue Abhaengigkeit.

Beim Durchfahren ueber ein PTY kamen zwei Dinge heraus:

keypad(True) loest die Pfeiltasten auf diesem Server nicht auf - getch()
liefert 27, 91, 66 statt KEY_DOWN, wofuer ein unpassendes terminfo
genuegt. Das fuehrende ESC haette als "zurueck" gegolten und den
Assistenten bei jedem Pfeildruck verlassen. Er loest die Sequenzen jetzt
selbst auf; ein einzelnes ESC wirkt weiterhin als Abbruch.

Und: Bricht die Verbindung weg, waehrend Kerio gestoppt ist, stirbt das
Script an SIGHUP und laesst den Dienst unten - genau so passiert, als der
Testtreiber die Verbindung schloss. ServiceController.abgesichert() faengt
SIGHUP, SIGTERM und SIGINT ab und startet den Dienst wieder, bevor der
Abbruch durchgereicht wird. Gegen den Testserver geprueft: Signal mitten
im Stopp-Fenster, Dienst kommt hoch, Daten unberuehrt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 14:54:33 +02:00

353 lines
14 KiB
Markdown

# kerio-connect-rename-user
Werkzeuge für Kerio Connect auf der Kommandozeile.
| Datei | Zweck |
| --- | --- |
| [`kerio_tui.py`](kerio_tui.py) | Assistent mit Menüführung — ohne Kommandozeilenparameter |
| [`kerio_rename_user.py`](kerio_rename_user.py) | Benutzer umbenennen — Login-Name **und** Mailbox-Verzeichnis im Store |
| [`kerio_users_config.py`](kerio_users_config.py) | Lesen und Ändern von `users.cfg` |
| [`kerio_common.py`](kerio_common.py) | Gemeinsame Bausteine: Admin-API-Client, Dienststeuerung |
Alles läuft **lokal auf dem Kerio-Server als root**, braucht nur die
Python-Standardbibliothek und bietet `--dry-run`.
## Der Assistent
Wer nicht mit Parametern hantieren will:
```bash
sudo ./kerio_tui.py
```
Der Assistent zeigt die vorhandenen Benutzer zur Auswahl, findet **verwaiste
Mailbox-Verzeichnisse von selbst** (Verzeichnisse ohne zugehörigen Benutzer),
fragt die nötigen Angaben ab und zeigt vor dem Ausführen den gleichwertigen
Kommandozeilenaufruf — wer ihn kennt, tippt ihn beim nächsten Mal direkt.
Bedienung: Pfeiltasten oder `j`/`k`, Enter bestätigt, `q` oder Esc geht zurück.
Geändert wird erst nach einer ausdrücklichen Bestätigung; bis dahin lässt sich
jeder Schritt abbrechen.
## Getestet
Gegen **Kerio Connect 10.0.9 patch 2** auf Debian 12, mit lizenziertem Server
und laufendem IMAP. Ein Benutzer mit gefüllter Mailbox wurde umbenannt und
danach geprüft:
| Prüfung | Ergebnis |
| --- | --- |
| IMAP-Login mit dem neuen Namen | funktioniert |
| IMAP-Login mit dem alten Namen | wird abgewiesen |
| Alle Mails in INBOX und Unterordner | vollständig vorhanden |
| Flags (`\Seen`, `\Flagged`) | erhalten |
| Mail-Dateien (`.eml`), md5 vorher/nachher | bitgleich |
| Neue Mail an die neue Adresse | `Result: delivered` |
| Mail an die alte Adresse | `550 5.1.1 Mailbox does not exist` |
| Verwaistes Verzeichnis unter dem alten Namen | keines |
| GUID und Passwort-Hash des Benutzers | unverändert |
Und für `--adopt`, mit gelöschtem Altbenutzer und neu angelegtem Zielbenutzer:
| Prüfung | Ergebnis |
| --- | --- |
| Alle 7 Mails beim neuen Benutzer sichtbar | ja, inklusive Unterordner und Flags |
| Kontaktkarte `.personal` | auf neuen Namen und Adresse umgeschrieben |
| `users.cfg` | unverändert |
| Neue Mail an den Zielbenutzer | zugestellt |
| Verwaistes Verzeichnis | keines übrig |
Der Assistent wurde über ein PTY durch alle Abläufe gefahren; dabei kam heraus,
dass `keypad(True)` auf diesem Server die Pfeiltasten **nicht** auflöst —
`getch()` liefert `27, 91, 66` statt `KEY_DOWN`. Ein fehlendes oder
unpassendes terminfo reicht dafür. Die Oberfläche löst die Sequenzen deshalb
selbst auf, sonst würde das führende ESC als „zurück" gelten und der Assistent
bei jedem Pfeildruck herausspringen.
Geändert haben sich nur Kerios eigene Index- und Statusdateien (`.journal.db`,
`status.fld`, `index.fld`) — die schreibt der Server bei jedem Zugriff neu.
Dazu Unit-Tests unter [tests/](tests/):
```bash
python3 tests/test_store.py
python3 tests/test_users_config.py
python3 tests/test_adopt.py
python3 tests/test_tui.py
```
---
# Benutzer umbenennen
## Warum das nicht trivial ist
Kerio hält den Benutzernamen an zwei Stellen, die nichts voneinander wissen:
| Wo | Was |
| --- | --- |
| `users.cfg` | Der Login-Name, in **zwei** Listen: `User` und `UserAdditionalData` |
| Dateisystem | `<store>/mail/<domain>/<loginname>/` — die eigentliche Mailbox |
Ändert man nur den Login-Namen, sucht Kerio ab sofort im Verzeichnis mit dem
*neuen* Namen, findet keins, legt ein leeres an — und die alten Mails liegen
weiter unter dem alten Verzeichnisnamen. Typischer Anlass für eine Umbenennung:
Heirat oder ein anderer Namenswechsel.
## Warum nicht über die Administration API
**Die API kann das nicht.** `Users.set` nimmt ein Feld `loginName` entgegen und
ignoriert es stillschweigend — kein Fehler, keine Wirkung. Nachgeprüft gegen
Kerio Connect 10.0.9 mit vier Varianten (nur `loginName`, mit `domainId`, mit
leeren `emailAddresses`, vollständiges User-Objekt): alle wirkungslos, während
`fullName` im selben Aufruf sauber übernommen wird.
Deshalb arbeitet das Script direkt auf `users.cfg` — und braucht dadurch
**keine Admin-Zugangsdaten**.
## Ablauf
1. **Vorprüfungen**, bevor irgendetwas geschrieben wird:
- Domain und Benutzer in `users.cfg` vorhanden?
- Benutzer aus einem Verzeichnisdienst (`InternalDb=0`)? → Abbruch, denn
dann gehört der Name dem Verzeichnisdienst
- neuer Login-Name frei und zeichenmäßig zulässig?
- Zielverzeichnis unbelegt, Quelle und Ziel auf demselben Dateisystem?
- Dienst steuerbar?
2. Plan ausgeben. `--dry-run` endet hier, sonst Rückfrage (`--yes` überspringt).
3. Dienst stoppen.
4. `users.cfg` **neu einlesen**, Name in `User` und `UserAdditionalData` setzen,
atomar über eine temporäre Datei speichern.
5. Verzeichnisse verschieben (`mail/`, und `archive/` falls vorhanden).
6. Dienst starten und gegenlesen.
**Schritte 4 und 5 liegen bewusst in einem einzigen Stopp-Fenster.** Das ist
keine Bequemlichkeit: Läuft Kerio zwischendurch mit nur einer der beiden
Hälften, legt es die vermeintlich fehlende Mailbox sofort neu an, und man hat
ein verwaistes Verzeichnis mehr. Genau das ist beim Entwickeln passiert.
Schlägt etwas fehl, werden verschobene Verzeichnisse zurückgenommen und
`users.cfg` aus dem Backup wiederhergestellt.
## Benutzung
```bash
# Wer ist da? (kein root nötig)
./kerio_rename_user.py --list
# Erst ansehen:
./kerio_rename_user.py \
--domain firma.de \
--old-login anna.mueller \
--new-login anna.schmidt \
--full-name "Anna Schmidt" \
--dry-run
# Dann wirklich:
sudo ./kerio_rename_user.py \
--domain firma.de \
--old-login anna.mueller \
--new-login anna.schmidt \
--full-name "Anna Schmidt"
```
Nur den angezeigten Namen ändern, ohne Login und Verzeichnis anzufassen:
```bash
sudo ./kerio_rename_user.py --domain firma.de \
--old-login anna.mueller --full-name "Anna Schmidt"
```
## Verwaistes Verzeichnis übernehmen (`--adopt`)
Für den Fall, dass der alte Benutzer **schon gelöscht** und der neue **schon
angelegt** ist — dann liegt nur noch das Mailbox-Verzeichnis herum und soll dem
neuen Benutzer zugeordnet werden:
```bash
sudo ./kerio_rename_user.py --adopt \
--domain firma.de \
--old-login anna.mueller \
--new-login anna.schmidt
```
`--old-login` ist hier der Name des **verwaisten Verzeichnisses**, `--new-login`
der **bereits existierende** Zielbenutzer. `users.cfg` wird dabei nicht
angefasst — es wandert nur das Verzeichnis.
Geprüft wird vorher:
- Der Zielbenutzer existiert in `users.cfg` (sonst liefe die Mailbox ins Leere).
- Der alte Benutzer existiert **nicht** mehr. Gibt es ihn noch, bricht das
Script ab und verweist auf die normale Umbenennung, die auch `users.cfg`
mitzieht.
- Hat der Zielbenutzer schon ein Postfach mit Mails darin, bricht das Script ab.
Mit `--force` wird es abgelöst: umbenannt nach
`<name>.abgeloest-<zeitstempel>`, danach rückt die übernommene Mailbox nach.
**Gelöscht wird nichts** — das alte Postfach liegt vollständig daneben und
kann nach einer Kontrolle von Hand weg.
Zusammengeführt wird bewusst nicht: Kerio führt eigene Indexdateien
(`index.fld`, `.journal.db`), die beim Hineinkopieren fremder Mails nicht mehr
passen würden. Das Verschieben eines vollständigen Verzeichnisses nimmt sie
dagegen mit.
Nach der Übernahme wird die Kontaktkarte des Benutzers (`.personal`) auf den
neuen Namen und die neue Adresse umgeschrieben, `stats.usr` beiseitegelegt —
die legt Kerio selbst neu an.
**Das Kennwort kommt nicht mit.** Der Zielbenutzer meldet sich weiterhin mit
seinem eigenen an; übernommen wird ausschließlich der Mailbestand.
## Optionen
| Option | Bedeutung |
| --- | --- |
| `--list` | Benutzer aus `users.cfg` auflisten |
| `--adopt` | Verwaistes Verzeichnis einem bestehenden Benutzer zuordnen |
| `--domain` | Mail-Domain, z. B. `firma.de` |
| `--old-login`, `--new-login` | Login-Namen ohne `@domain` |
| `--full-name` | Neuer angezeigter Name |
| `--install-dir` | Standard `/opt/kerio/mailserver` |
| `--store-dir` | Standard `/opt/kerio/mailserver/store` |
| `--service-name` | Dienstname, Standard `kerio-connect` |
| `--service-manager` | `auto`, `systemd`, `initd` oder `none` |
| `--service-wait` | Sekunden Wartezeit aufs Stoppen, Standard 90 |
| `--dry-run` | Nur anzeigen |
| `--yes` | Rückfrage überspringen |
| `--force` | Bei Verzeichnisdienst-Benutzern; mit `--adopt`: belegtes Ziel beiseiteschieben |
`--service-manager none` fasst den Dienst nicht an — dafür muss Kerio dann
selbst gestoppt sein, bevor das Script läuft.
## Die Kontaktkarte
`<mailbox>/.personal` ist die persönliche vCard des Benutzers und trägt seinen
Namen und seine Adresse. Das Script schreibt sie in beiden Modi auf den neuen
Stand um — Adresse, `FN:` und die Betreffzeile.
Löschen wäre keine Alternative: **Kerio legt die Datei nicht neu an**, wenn sie
fehlt. Weder beim Dienstneustart noch bei einer Änderung am Benutzer über die
Admin-API (geprüft gegen 10.0.9). Der Benutzer stünde dauerhaft ohne eigene
Kontaktkarte da.
## Was das Script bewusst nicht anfasst
Der alte Name bleibt an zwei Stellen stehen, die reine Anzeige betreffen und den
Mailbetrieb nicht stören:
- `#public/Contacts/` — der Eintrag in der globalen Adressliste
- `.caldav.db` / `.carddav.db` — die DAV-Datenbanken
Wer die sofort korrekt haben will, korrigiert den Kontakt in der
Administrationskonsole.
Kommt der alte Name in `users.cfg` außerhalb der Benutzerlisten vor (etwa in
einem Alias), meldet das Script das im Plan und ändert es **nicht** automatisch —
lieber ein Hinweis als eine kaputte Konfiguration.
Die alte Adresse nimmt nach der Umbenennung keine Mail mehr an. Wer das braucht,
legt anschließend in der Administrationskonsole einen Alias an.
## Hinweise
- **Vorher ein Backup des Stores anlegen.** Das Script verschiebt Verzeichnisse.
- Erst an einem Testbenutzer ausprobieren.
- Der Benutzer sollte während des Laufs nicht angemeldet sein.
- Bricht die SSH-Verbindung weg, während Kerio gestoppt ist, fängt das Script
das Signal ab und **startet den Dienst wieder**, bevor es sich beendet.
Verlassen sollte man sich darauf trotzdem nicht — besser in `tmux` oder
`screen` arbeiten.
- Nach der Umbenennung müssen sich alle Mail-Clients mit dem neuen Login neu
anmelden.
- Gruppenmitgliedschaften bleiben erhalten: Kerio referenziert Gruppen über
GUIDs, nicht über Namen.
---
# Testlizenz besorgen
Der Erstkonfigurationsassistent verlangt im Schritt „Registrierte Testaktivierung"
eine Testlizenznummer samt CAPTCHA. Der Link „Lizenznummer für Testversion
erhalten" im Assistenten zeigt noch auf die alte `kerio.com`-Adresse und läuft
ins Leere: GFI hat die Domain auf **`gfi.ai`** umgestellt.
Die funktionierende Adresse — dort die E-Mail-Adresse eintragen, die Nummer kommt
per Mail:
**<https://gfi.ai/products-and-solutions/email-and-messaging-solutions/kerioconnect/free-trial>**
Die alten Adressen `www.gfi.com/.../kerio-connect/download` und
`gfi.ai/.../kerio-connect/download` leiten inzwischen alle dorthin um.
Die Nummer lässt sich entweder im Assistenten eintragen oder später aus der
laufenden Instanz heraus: **Dashboard → „Become a registered trial user"**.
Beides braucht ausgehendes HTTPS auf Port 443.
## Für jeden Testlauf eine frische E-Mail-Adresse
**GFI gibt pro E-Mail-Adresse dauerhaft dieselbe Trial-Nummer zurück.** Wer sich
mit einer Adresse schon einmal registriert hat, bekommt bei jeder weiteren
Anfrage seinen alten Schlüssel — und wenn dessen 30 Tage abgelaufen sind, ist er
es auch beim Neuanfordern. Der Server quittiert das mit:
```
registration.cpp: License error: Unable to set license (License is expired).
```
Das sieht nach einem Server- oder Netzwerkproblem aus, ist aber keines: Der
Schlüssel ist schlicht der alte. Für einen neuen Testzeitraum braucht es eine
Adresse, mit der noch nie registriert wurde.
Wegwerfadressen (trashmail.com und ähnliche) funktionieren dafür, werden von der
Anmeldeseite aber teilweise blockiert — dann hilft nur ein anderer Anbieter.
## Ohne Lizenz geht kein Mailbetrieb
Der Schalter `ConfigWizardDone` in `mailserver.cfg` überspringt zwar den
Assistenten und gibt Administrationskonsole und Admin-API frei — er aktiviert
aber **keinen Testzeitraum**. Ohne Lizenzschlüssel weisen IMAP, POP3 und Webmail
jede Verbindung ab (`Server license expired` beim Client, `Product name does not
match` im Log), und `error.log` meldet beim Start `No license key found`. Eine
API zum Aktivieren gibt es nicht.
Wer den Assistenten neu durchlaufen will, setzt `ConfigWizardDone` zurück auf `0`
oder löscht `mailserver.cfg` ganz — Kerio legt beim nächsten Start eine frische
an. Achtung: die Domänendefinition steht in dieser Datei, die Benutzer in
`users.cfg` sind danach verwaist.
**`mailserver.cfg` und `users.cfg` dürfen nur bei gestopptem Dienst bearbeitet
werden.** Kerio schreibt seine Konfiguration beim Beenden aus dem Speicher
zurück und überschreibt sonst jede Änderung am laufenden Dienst.
## Wenn der Schlüssel abgelehnt wird
`store/logs/error.log` unterscheidet die Fälle — die Meldung sagt, ob der
Schlüssel *ungültig* oder *abgelaufen* ist. Bei `License is expired` zuerst die
E-Mail-Adresse prüfen (siehe oben), das ist die häufigste Ursache.
Erst danach lohnt die Netzwerkseite:
```bash
# Registrierungsserver erreichbar?
getent hosts secure.kerio.com # muss auflösen
getent hosts registration.kerio.com # löst NICHT mehr auf (normal)
# Uhr korrekt? Eine falsche Systemzeit lässt gültige Lizenzen ablaufen.
timedatectl
```
Der alte Host `registration.kerio.com` existiert nicht mehr; `secure.kerio.com`
ist der aktive Registrierungsserver.
---
## Referenzen
- [Administration API — Users](https://manuals.gfi.com/en/kerio/api/connect/admin/reference/interfacekerio_1_1jsonapi_1_1admin_1_1_users.html)
- [Sample communication (Session.login, X-Token)](https://manuals.gfi.com/en/kerio/api/connect/admin/reference/sample_communication.html)
- [Registering Kerio Connect (unregistered mode)](https://manuals.gfi.com/en/kerio/connect/content/registration-and-licenses/registering-kerio-connect-1134.html)
- [Kerio Connect Testversion (30 Tage)](https://gfi.ai/products-and-solutions/email-and-messaging-solutions/kerioconnect/free-trial)
- [Modifying the mailserver.cfg](https://support.kerioconnect.gfi.com/en-us/article/114788-modifying-the-mailserver-cfg)