CentOS/RHEL/Oracle Linux – system po przeniesieniu na inną maszynę nie startuje (problem z Dracut)

Przeczytasz to w: 2 minut

Problem wygląda tak i występuje w CentOS 7/Red Hat Enterprise 7/Oracle Linux/podobne:

Rozwiązaniem jest wygenerowanie nowszych plików do Dracuta. Można to zrobić za pomocą płyty ratunkowej do odpowiedniej dystrybucji. W tym przypadku będę bazował na Oracle Linuxie 7.6. Po starcie płyty ratunkowej na maszynie, na której jest problem należy odpalić shell, w którym będziemy wykonywać polecenia wybierając opcję 1 z menu, tak jak tutaj:

Następnie jeśli nasza partycja zostanie wykryta, należy wykonać polecenie chroot /mnt/sysimage i od tego momentu jesteśmy w stanie pracować w systemie na naszym dysku, który się nie odpala.

Następnie należy wykonać polecenie:

dracut -f /boot/initramfs-4.14.35-1844.2.5.el7uek.x86_64.img 4.14.35-1844.2.5.el7uek.x86_64

Oczywiście w poleceniu jest wersja kernela, która jest aktualnie na serwerze, który obsługiwałem. Tutaj trzeba dopasować własną wersję 😊

Po tym wystarczy zamknąć shell poleceniem exit i zrestartować serwer poleceniem reboot i próbując odpalić system. Efekt jest taki:

IMAPsync czyli zbawienie dla migracji serwerów pocztowych oraz kilka słów dlaczego nie warto korzystać z poczty Onetu i WP.pl

Przeczytasz to w: 23 minut

Czasami zdarza się taki moment, że nas serwer jest za stary, by go migrować i trzeba jakoś przenieść serwer, czasami admini chcą zmienić serwer pocztowy na jakieś inne rozwiązanie typu przenieść się na serwer Exchange z Postfix/Dovecot, lub po prostu zmienić dostawcę pocztowego, bo ileż można dostawać spam od Onetu czy WP? Poza takimi błahostkami jak przeniesienie prywatnej skrzynki pocztowej te narzędzie pozwala na masowe przenoszenie skrzynek. Jedyny minus rozwiązania jest taki, że trzeba zresetować wszystkim hasła na czas migracji.

Postaram się pokazać kilka scenariuszy przenoszenia skrzynek, przy czym w dużej mierze początkowa instalacja zawsze jest taka sama – jedyna różnica jest w ustawieniach programu. IMAPsync jest aplikacją, która zadziała na Windowsie i Linuksie, ale szczerze powiedziawszy miałem problem z jej działaniem spod Windowsa, więc używam Linuksa do operacji na nim. W przypadku posiadania Windowsa używam Linux Subsystem for Windows (WSL), bo dzięki temu na tym samym hoście można korzystać na wybranej dystrybucji Linuksa bez jakichkolwiek problemów.

Pierwszą rzeczą, którą należy zrobić jest włączenie funkcji w Windows 10/Windows Server 2016/Windows Server 2019:

Następnie, w przypadku Windows 10 znajdujemy w Microsoft Store aplikację o nazwie Ubuntu 18.04 (miałem problemy z działaniem IMAPsync na 20.04, prawdopodobnie ze względu na inną wersję OpenSSL) i ją instalujemy:

W Windowsie Server jest o tyle inaczej, że nie ma tam Microsoft Store. Taką paczkę należy pobrać z Internetu i zmienić jej format na .zip, bo w rzeczywistości to jest archiwum. Całość jest opisana w tym dokumencie. Na wypadek, gdyby zniknął, ściągamy z tego linku plik.

Zanim odpalimy aplikację, musimy uruchomić system ponownie. Jeśli tego nie zrobimy, najpewniej zobaczymy ten błąd:

W przypadku Windows Server należy odpalić aplikację ubuntu1804.exe, która jest wewnątrz rozpakowanego archiwum.

Po restarcie należy zdefiniować konto użytkownika i hasło:

Po tym należy wykonać polecenia, aby zainstalować IMAPsynca:

sudo apt update
sudo apt install libauthen-ntlm-perl libclass-load-perl libcrypt-ssleay-perl libdata-uniqid-perl libdigest-hmac-perl libdist-checkconflicts-perl \
libencode-imaputf7-perl libfile-copy-recursive-perl libfile-tail-perl libio-compress-perl libio-socket-inet6-perl libio-socket-ssl-perl libio-tee-perl \
libmail-imapclient-perl libmodule-scandeps-perl libnet-dbus-perl libnet-ssleay-perl libpar-packer-perl libreadonly-perl libregexp-common-perl \
libsys-meminfo-perl libterm-readkey-perl libtest-fatal-perl libtest-mock-guard-perl libtest-mockobject-perl libtest-pod-perl libtest-requires-perl \
libtest-simple-perl libunicode-string-perl liburi-perl libtest-nowarnings-perl libtest-deep-perl libtest-warn-perl make cpanminus apt-file libcrypt-openssl-rsa-perl libjson-webtoken-perl libcrypt-openssl-bignum-perl libcgi-pm-perl
sudo cpanm CGI
git clone https://github.com/imapsync/imapsync
cd imapsync/INSTALL.d
sudo ./prerequisites_imapsync

Jeśli wynik jest następujący – powinniśmy dostać mniej więcej następujący wynik:

supra@supra-pc:~/imapsync/INSTALL.d$ sudo ./prerequisites_imapsync
$SHELL says  /bin/bash
$0 gives  ./prerequisites_imapsync
ps -ef gives root     15542 15541  0 10:42 tty1     00:00:00 /bin/sh ./prerequisites_imapsync
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:        18.04
Codename:       bionic
Linux supra-pc 4.4.0-19041-Microsoft #1-Microsoft Fri Dec 06 14:06:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
Ok: Found Perl 5.26.1
make: Nothing to be done for 'foo'.
Ok: Found make GNU Make 4.1
Ok: Found Perl module App::cpanminus
Ok: Found Perl module Authen::NTLM
Ok: Found Perl module CGI
Ok: Found Perl module Compress::Zlib
Ok: Found Perl module Crypt::OpenSSL::RSA
Ok: Found Perl module Data::Dumper
Ok: Found Perl module Data::Uniqid
Ok: Found Perl module Digest::HMAC
Ok: Found Perl module Digest::HMAC_MD5
Ok: Found Perl module Digest::MD5
Ok: Found Perl module Dist::CheckConflicts
Ok: Found Perl module Encode
Ok: Found Perl module Encode::Byte
Ok: Found Perl module Encode::IMAPUTF7
Ok: Found Perl module File::Copy::Recursive
Ok: Found Perl module File::Tail
Ok: Found Perl module IO::Socket::INET
Ok: Found Perl module IO::Socket::INET6
Ok: Found Perl module IO::Socket::SSL
Ok: Found Perl module IO::Tee
Ok: Found Perl module JSON
Ok: Found Perl module JSON::WebToken
Ok: Found Perl module JSON::WebToken::Crypt::RSA
Ok: Found Perl module HTML::Entities
Ok: Found Perl module LWP::UserAgent
Ok: Found Perl module Mail::IMAPClient
Ok: Found Perl module MIME::Base64
Ok: Found Perl module Module::Implementation
Ok: Found Perl module Module::Runtime
Ok: Found Perl module Module::ScanDeps
Ok: Found Perl module Net::SSLeay
Ok: Found Perl module Package::Stash
Ok: Found Perl module Package::Stash::XS
Ok: Found Perl module PAR::Packer
Ok: Found Perl module Parse::RecDescent
Ok: Found Perl module Pod::Usage
Ok: Found Perl module Readonly
Ok: Found Perl module Regexp::Common
Ok: Found Perl module Sys::MemInfo
Ok: Found Perl module Term::ReadKey
Ok: Found Perl module Test::Fatal
Ok: Found Perl module Test::Mock::Guard
Ok: Found Perl module Test::MockObject
Ok: Found Perl module Test::More
Ok: Found Perl module Test::Pod
Ok: Found Perl module Test::Requires
Ok: Found Perl module Test::Deep
Ok: Found Perl module Text::ParseWords
Ok: Found Perl module Try::Tiny
Ok: Found Perl module Unicode::String
Ok: Found Perl module URI::Escape
All needed modules are already installed
Ok: Found cpanm cpanm (App::cpanminus) version 1.7043 (/usr/bin/cpanm)

Mając to można wrócić do głównego katalogu sklonowanego repozytorium Gita i zanim odpalimy IMAPsync warto sprawdzić dane do serwera pocztowego. Aby wykonać synchronizację, należy podać dane skrzynki, z której synchronizujemy wiadomości:

  • adres serwera pocztowego (opcja --host1),
  • port serwera pocztowego (opcja --port1, często opcjonalne, bo IMAPsync w przypadku prawidłowo zdefiniowanych wpisów w DNS sam wykryje odpowiedni port),
  • nazwa konta użytkownika (opcja --user1),
  • hasło konta użytkownika (opcja --password1),
  • wymuszenie wykorzystywania SSL (opcja --ssl1).

To samo podajemy dla docelowego serwera i użytkownika, lecz wykorzystujemy parametry z numerkiem 2 na końcu (np. --host2).

Wcześniej warto sprawdzić na jakim porcie serwer pocztowy nasłuchuje. Poniżej wykonuję test dla serwera OVH, to znaczy ssl0.ovh.net:

supra@supra-pc:/mnt/r/supra/Pobrane/imapsync-imapsync-1.945$ openssl s_client -connect ssl0.ovh.net:993 --showcerts -servername ssl0.ovh.net
CONNECTED(00000003)
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
verify return:1
depth=0 CN = ssl0.ovh.net
verify return:1
---
Certificate chain
 0 s:CN = ssl0.ovh.net
   i:C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
-----BEGIN CERTIFICATE-----
MIIGujCCBaKgAwIBAgIRAKNd5nTWqiwzvsziDTAPdk4wDQYJKoZIhvcNAQELBQAw
gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE
AxMuU2VjdGlnbyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD
QTAeFw0yMDA0MjgwMDAwMDBaFw0yMTA0MjgyMzU5NTlaMBcxFTATBgNVBAMTDHNz
bDAub3ZoLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOmVmvbx
5Wl7HnDdKosd1scDKTX+7osHcSFOMM2zPlU9NDO26SuilV0avXQjzHPKlK99GY3t
47CFaLTlvWeNXJDnYcN+KoPznM3OFdiPfLufeOYpKrLO+RJi1WDfvrLaQgctKJSw
+SipYB0HblWQaH6eJQjVp67LJA6NGqGOLxrHJEAL1a5DnzRKd8WFaXusf+5iwtEu
uSsLAflCx8kel8F0nWKI+knj1nYalb98vrUdsrcGLUkeF990ZwETrx6RI4/GWwpq
kuSn3tmxtyWXhTQgkiNh6hDz3+AVQTp1v42rxynRNgzANRc1XX37qYV8fbVEbnfj
/BGTLrMylf130QKvCXhh2xkp99KGJpHSesodkzFthl19LuTm3mp2CDdF227+QTsZ
YY0ZDPOxrpvGNPskXgfQupGMCqaxB215SbbORKNhht8fT4wcR25Z+bfpvvwlGHCh
PccIOXqaHLjHc8/dv2G8t66XPFkpmf+LGzpvR4P0RT6i6G3NUYHBr+4Adxv46nuh
BDJVwWDfcemdbxZ9di5JDfb7cRENJox0vB4roQKR23rbIrgpyCwu9MjfviWanlOr
vUuu9zgNli9YZPEXmXjpL7936tesT7uUuCEhRCCecejYG8TUeojpXUOVMCcnm9tc
ixHBA11A13lochGzdPumTlYl3pOTZm8vc/khAgMBAAGjggKGMIICgjAfBgNVHSME
GDAWgBSNjF7EVK2K4Xfpm/mbBeG4AY1h4TAdBgNVHQ4EFgQU3ms/wnSQLdy8OIWc
6MFBUpw0Z2cwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAgcw
JTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIB
MIGEBggrBgEFBQcBAQR4MHYwTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jcnQuc2VjdGln
by5jb20vU2VjdGlnb1JTQURvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5j
cnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMCkGA1UdEQQi
MCCCDHNzbDAub3ZoLm5ldIIQd3d3LnNzbDAub3ZoLm5ldDCCAQQGCisGAQQB1nkC
BAIEgfUEgfIA8AB2AH0+8viP/4hVaCTCwMqeUol5K8UOeAl/LmqXaJl+IvDXAAAB
ccEJ9CIAAAQDAEcwRQIhAO/y/kRhgbJNJjoaAvoch5wfTSwPaK2JIvrVaP1SFQmW
AiBeCdRgQqBVxGmNCFrIAP/jN4afQVhOeZJrIcHJmANV7wB2AJQgvB6O1Y1siHMf
gosiLA3R2k1ebE+UPWHbTi9YTaLCAAABccEJ9EgAAAQDAEcwRQIhAOtOEaYg+esw
zZZSL9mm8XKq2v6kRCGA7/ZNPZWE1lc6AiAdj0lzPvyJD0oc3mOHDR4mdlfnLrY9
4x5uc5xknWh9PDANBgkqhkiG9w0BAQsFAAOCAQEATmrjXr1OguegMTm5H1yHcd/2
lGyPL/Hl7uBL069XOgZ3k2t7F25CWBkGsB6dzI7Qpwr9ODlPR1U8c/Y59X5rOjaR
AZraW2jAd96n2Yc6155WvwENQbgCwS0iMn5u1V3z+M1TG4FI7B30dEOFvMsljGIF
j7gn8LH+BxZMB/+ch6qY0huXy3K5A53OX4Ten85UVKuZBiG3yxvzfFX5mlY7PnDf
zcFGxc3SvcnTZS0HYHE+qv7SzpkuvBc4p/TIKu6zuCtNjwZJpSoJ6p/272dFMzav
ToVNMOK0AVYARP8W0mYeWfzIor+sjIwRshNrUbi112PKxhcozm9KW8tbagmw8w==
-----END CERTIFICATE-----
 1 s:C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA
   i:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
-----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
-----END CERTIFICATE-----
 2 s:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
   i:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
---
Server certificate
subject=CN = ssl0.ovh.net

issuer=C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Domain Validation Secure Server CA

---
No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 5698 bytes and written 397 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: 94C2704B41535450C2E914E258FCF4261AE3830EBAF68050A459650A70DD6AE6
    Session-ID-ctx:
    Master-Key: 78941A4567E592C77B7767DBBC5046B91A108F7B2C7A1ED057C274F8C896337894BD28715CCF43EB981A9832DB147E15
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 7d 83 2f ee 41 40 4d f7-7b 99 ea d7 5f 6e 3b 68   }./.A@M.{..._n;h
    0010 - 05 37 73 e7 89 63 2e 0a-ad 25 23 3f 28 d7 3e ed   .7s..c...%#?(.>.
    0020 - e4 e6 d4 33 52 10 24 49-84 93 7f 33 72 ed 50 20   ...3R.$I...3r.P
    0030 - 9b 55 40 21 01 86 99 37-21 78 bc 04 cb 4c 3a c7   .U@!...7!x...L:.
    0040 - ee 7a 29 45 d3 d0 88 a2-5c 4a d4 bc 56 54 71 0a   .z)E....\J..VTq.
    0050 - c4 e6 85 a1 4e 66 2d 46-7e e9 f2 03 63 97 e9 33   ....Nf-F~...c..3
    0060 - 1b a7 2c f2 9d da 93 03-bc d7 6b d2 c8 84 13 15   ..,.......k.....
    0070 - 46 05 d0 54 ce e5 e8 2a-41 7f 9b 15 a1 00 8a da   F..T...*A.......
    0080 - ff 8a ce 11 91 83 59 4a-47 be d5 18 da 47 4d a7   ......YJG....GM.
    0090 - d4 73 7a 5c 39 a1 21 ac-2b 5e 62 f4 47 ba fc e4   .sz\9.!.+^b.G...
    00a0 - e1 06 7d 80 81 53 9e 00-88 c7 13 d2 bc 07 a0 88   ..}..S..........

    Start Time: 1592435499
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
---
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot on host 103 ready

* BAD Error in IMAP command received by server.

* BAD Error in IMAP command received by server.

* BYE Too many invalid IMAP commands.
closed

Na końcu komunikacji możemy zobaczyć jakie funkcjonalności ma ten serwer IMAP i możemy po tym nagłówku poznać jakie metody uwierzytelnienia są dostępne dla tego serwera. Poniżej kilka działajacych przykładów wykorzystania IMAPsync dla pojedynczej skrzynki:

Z serwera OVH na własny serwer

./imapsync --host1 ssl0.ovh.net --port1 993 --user1 test@test.com --password1 haslo123 --host2 mail.etf2l.site --user2 supra@etf2l.site --password2 haslo123 --ssl1 -ssl2

Z serwera GMail na własny serwer

./imapsync --host1 imap.gmail.com --port1 993 --user1 test@gmail.com --password1 haslo123 --host2 mail.etf2l.site --user2 supra@etf2l.site --password2 haslo123 --ssl1 -ssl2

Przy przykładzie z GMailem warto zerknąć na informacje dotyczące odblokowywania możliwości synchronizacji poniżej.

Z serwera Politechniki Śląskiej na własny serwer

./imapsync --host1 poczta.student.polsl.pl --port1 993 --user1 kontostudenckie@student.polsl.pl --password1 haslo123 --host2 mail.etf2l.site --user2 polsl@etf2l.site --password2 haslo --ssl1 -ssl2

Z serwera Onet.pl na serwer GMail

Przed synchronizacją należy włączyć obsługę IMAP dla konta oraz „dostęp do mniej bezpiecznych aplikacji”:

Taki problem da się też rozpoznać po logu:

Host2 capability before authentication: IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH AUTH
Host2 failure: Error login on [imap.gmail.com] with user [test@gmail.com] auth [LOGIN]: 2 NO [ALERT] Your account is not enabled for IMAP use. Please visit your Gmail settings page and enable your account for IMAP access. (Failure)
Exiting with return value 16 (EXIT_AUTHENTICATION_FAILURE)
Disconnecting from host1 imap.poczta.onet.pl user1 test@onet.pl
Log file is LOG_imapsync/2020_07_23_08_39_05_281_test@onet.pl_test@gmail.com.txt ( to change it, use --logfile filepath ; or use --nolog to turn off logging )

Końcowe polecenie jest takie:

./imapsync --host1 imap.poczta.onet.pl --user1 test@onet.pl --password1 "password123" --host2 imap.gmail.com --port2 993 --user2 test@gmail.com --password2 "password123" --ssl1 -ssl2

Przy okazji odpowiedź na pytanie czemu ja zawsze dostaję tak dużo spamu na moją skrzynkę? – otóż dlatego:

W trakcie rejestracji konta aby mieć skrzynkę za darmo, należy zaznaczyć odpowiednią zgodę, lecz ludzie z reguły nie czytają tego i klikają opcję na samej górze. To powoduje, że Onet.pl i ich partnerzy będą za Waszym przyzwoleniem wysyłać do Was spam. Po kliknięciu Załóż konto jednak przekonuje się, że się myliłem:

Ponadto ich oferta cenowa ze skrzynkami dla prywatnych użytkowników to żart w 2020 roku (np. GMail daje to za darmo (nie do końca, bo mogą zbierać dane o użytkownikach, ale funkcjonalnie i bez spamu za darmo)). Inna rzecz, która mnie zaskoczyła to to, że mogłem zarejestrować konto z jednym z najprostszych haseł słownikowych: Zaq12wsx!.

Z serwera WP.pl na serwer GMail

W WP.pl jest ta sama śpiewka, co w Onet.pl z mailami marketingowymi i tym, że da się założyć konto z hasłem Zaq12wsx!, ale przynajmniej Ci zaznaczyli, że te hasło jest kiepskie:

Tutaj podobnie jak w GMail synchronizacja po IMAP jest domyślnie wyłączona, trzeba ją włączyć:

Host2 failure: Error login on [imap.wp.pl] with user [test@wp.pl] auth [LOGIN]: 2 NO Wybrany kanal dostepu nalezy aktywowac w intefejsie WWW
Exiting with return value 16 (EXIT_AUTHENTICATION_FAILURE)
./imapsync --host1 imap.wp.pl --user1 test@wp.pl --password1 "password123" --host2 imap.gmail.com --port2 993 --user2 test@gmail.com --password2 "password123" --ssl1 -ssl2

Z serwera Gazeta.pl na serwer GMail

Tutaj spamik ponownie, ale tym razem da się wyłączyć:

Jednak nie zaznaczyło „powyższej” opcji:

Co ciekawe, wg Gazeta.pl Zaq12wsx! to mocne hasło:

Tutaj jedynie SMTP jest wyłączony (uwaga, gdyby ktoś z tej skrzynki chciał korzystać w Outlooku czy innym kliencie pocztowym). IMAP jest włączony, więc od razu można puścić synchronizację:

./imapsync --host1 imap.gazeta.pl --user1 test@gazeta.pl --password1 "password123" --host2 imap.gmail.com --port2 993 --user2 test@gmail.com --password2 "password123" --ssl1 -ssl2

Z serwera o2.pl na serwer GMail

Interfejs jest identyczny jak ten z WP.pl, te same zgody, te same hasło:

Tak samo jak na WP.pl odpalamy IMAPa:

./imapsync --host1 poczta.o2.pl --user1 test@o2.pl --password1 "password123" --host2 imap.gmail.com --port2 993 --user2 test@gmail.com --password2 "password123" --ssl1 -ssl2

Z własnego serwera na Exchange Online

./imapsync --host1 ssl0.ovh.net --port1 993 --user1 test@test.com --password1 "password123" --host2 outlook.office365.com --user2 test@test.onmicrosoft.com --password2 "password123" --ssl1 -ssl2

Przykład wyniku synchronizacji małej skrzynki:

supra@supra-pc:/mnt/r/supra/Pobrane/imapsync-imapsync-1.945$ ./imapsync --host1 ssl0.ovh.net --port1 993 --user1 test@test.com --password1 "password123" --host2 imap.poczta.onet.pl --user2 test@onet.pl --password2 "password123"
--ssl1 -ssl2
Here is imapsync 1.945 on host supra-pc, a linux system with 16.5/63.9 free GiB of RAM
with Perl 5.26.1 and Mail::IMAPClient 3.42
Transfer started at Thu Jul 23 08:12:33 2020
PID is 38 my PPID is 8
Log file is LOG_imapsync/2020_07_23_08_12_33_744_test@test.com_test@onet.pl.txt ( to change it, use --logfile path ; or use --nolog to turn off logging )
Load is 0.52 0.58 0.59 1/5 on 16 cores
Current directory is /mnt/r/supra/Pobrane/imapsync-imapsync-1.945
Real user id is supra (uid 1000)
Effective user id is supra (euid 1000)
$RCSfile: imapsync,v $ $Revision: 1.945 $ $Date: 2019/06/26 19:30:56 $
Command line used, run by /usr/bin/perl:
./imapsync --host1 ssl0.ovh.net --port1 993 --user1 test@test.com --password1 MASKED --host2 imap.poczta.onet.pl --user2 test@onet.pl --password2 MASKED --ssl1 -ssl2
Temp directory is /tmp ( to change it use --tmpdir dirpath )
kill -QUIT 38 # special behavior: call to sub catch_exit
kill -TERM 38 # special behavior: call to sub catch_exit
kill -INT 38 # special behavior: call to sub catch_reconnect
kill -HUP 38 # special behavior: call to sub catch_print
kill -USR1 38 # special behavior: call to sub toggle_sleep
File /tmp/imapsync.pid does not exist
PID file is /tmp/imapsync.pid ( to change it, use --pidfile filepath ; to avoid it use --pidfile "" )
Writing my PID 38 in /tmp/imapsync.pid
Writing also my logfile name in /tmp/imapsync.pid : LOG_imapsync/2020_07_23_08_12_33_744_test@test.com_test@onet.pl.txt
Modules version list:
Authen::NTLM         1.09
CGI                  4.49
Compress::Zlib       2.074
Crypt::OpenSSL::RSA  0.28
Data::Uniqid         0.12
Digest::HMAC_MD5     1.01
Digest::HMAC_SHA1    1.03
Digest::MD5          2.55
File::Copy::Recursive 0.40
File::Spec           3.67
Getopt::Long         2.49
HTML::Entities       3.69
IO::Socket           1.38
IO::Socket::INET     1.35
IO::Socket::INET6    2.72
IO::Socket::IP       0.38
IO::Socket::SSL      2.060
IO::Tee              0.65
JSON                 4.02
JSON::WebToken       0.10
LWP                  6.31
Mail::IMAPClient     3.42
Net::Ping            2.55
Net::SSLeay          1.84
Term::ReadKey        2.37
Test::MockObject     1.20161202
Time::HiRes          1.9741
URI::Escape          3.31
Unicode::String      2.10
( use --no-modulesversion to turn off printing this Perl modules list )
Info: will resync flags for already transferred messages. Use --noresyncflags to not resync flags.
SSL debug mode level is --debugssl 1 (can be set from 0 meaning no debug to 4 meaning max debug)
Host1: SSL default mode is like --sslargs1 "SSL_verify_mode=0", meaning for host1 SSL_VERIFY_NONE, ie, do not check the certificate server.
Host1: Use --sslargs1 SSL_verify_mode=1 to have SSL_VERIFY_PEER, ie, check the certificate server of host1
Host2: SSL default mode is like --sslargs2 "SSL_verify_mode=0", meaning for host2 SSL_VERIFY_NONE, ie, do not check the certificate server.
Host2: Use --sslargs2 SSL_verify_mode=1 to have SSL_VERIFY_PEER, ie, check the certificate server of host2
Info: turned ON syncinternaldates, will set the internal dates (arrival dates) on host2 same as host1.
Host1: will try to use LOGIN authentication on host1
Host2: will try to use LOGIN authentication on host2
Host1: imap connection timeout is 120 seconds
Host2: imap connection timeout is 120 seconds
Host1: IMAP server [ssl0.ovh.net] port [993] user [test@test.com]
Host2: IMAP server [imap.poczta.onet.pl] port [993] user [test@onet.pl]
Host1: connecting and login on host1 [ssl0.ovh.net] port [993] with user [test@test.com]
Host1 IP address: 193.70.18.144
Host1 banner: * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot on host 103 ready
Host1 capability before authentication: IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN AUTH
Host1: ssl0.ovh.net says it has CAPABILITY for AUTHENTICATE LOGIN
Host1: success login on [ssl0.ovh.net] with user [test@test.com] auth [LOGIN]
Host2: connecting and login on host2 [imap.poczta.onet.pl] port [993] with user [test@onet.pl]
Host2 IP address: 213.180.147.154
Host2 banner: * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID SORT SORT=DISPLAY MULTIAPPEND UNSELECT CHILDREN UIDPLUS LIST-STATUS LIST-EXTENDED I18NLEVEL=1 SEARCHRES WITHIN AUTH=PLAIN AUTH=LOGIN AUTH=XOAUTH2] Onet server ready.
Host2 capability before authentication: IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID SORT SORT=DISPLAY MULTIAPPEND UNSELECT CHILDREN UIDPLUS LIST-STATUS LIST-EXTENDED I18NLEVEL=1 SEARCHRES WITHIN AUTH=PLAIN AUTH=LOGIN AUTH=XOAUTH2 I18NLEVEL AUTH
Host2: imap.poczta.onet.pl says it has CAPABILITY for AUTHENTICATE LOGIN
Host2: success login on [imap.poczta.onet.pl] with user [test@onet.pl] auth [LOGIN]
Host1: state Authenticated
Host2: state Authenticated
Host1 capability once authenticated: IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE QUOTA THREAD I18NLEVEL CONTEXT
Host2 capability once authenticated: IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID SORT SORT=DISPLAY MULTIAPPEND UNSELECT CHILDREN UIDPLUS LIST-STATUS LIST-EXTENDED I18NLEVEL=1 SEARCHRES WITHIN I18NLEVEL

Host1: found ID capability. Sending/receiving ID, presented in raw IMAP for now.
In order to avoid sending/receiving ID, use option --noid
Sending: 4 ID ("name" "imapsync" "version" "1.945" "os" "linux" "vendor" "Gilles LAMIRAL" "support-url" "https://imapsync.lamiral.info/" "date" "26-Jun-2019 19:30:56 +0000" "side" "host1")
Sent 181 bytes
Read:   * ID ("name" "Dovecot")
        4 OK ID completed (0.000 + 0.000 secs).


Host2: found ID capability. Sending/receiving ID, presented in raw IMAP for now.
In order to avoid sending/receiving ID, use option --noid
Sending: 4 ID ("name" "imapsync" "version" "1.945" "os" "linux" "vendor" "Gilles LAMIRAL" "support-url" "https://imapsync.lamiral.info/" "date" "26-Jun-2019 19:30:56 +0000" "side" "host2")
Sent 181 bytes
Read:   * ID ("name" "NIL")
        4 OK ID completed (0.001 + 0.000 secs).

Host1: found 13 folders.
Host2: found 8 folders.
Host1: guessing separator from folder listing: [.]
Host1: separator given by NAMESPACE: [.]
Host2: guessing separator from folder listing: [/]
Host2: No NAMESPACE capability, so using guessed separator [/]
You can set the separator character with the --sep2 option,
the complete listing of folders may help you to find it
[Powiadomienia]
[Oferty]
[Spo&AUI-eczno&AVs-ci]
[Drafts]
[Junk]
[Sent]
[Trash]
[INBOX]
Host1: guessing prefix from folder listing: [INBOX.]
Host1: prefix given by NAMESPACE: [INBOX.]
Host2: guessing prefix from folder listing: []
Host2: No NAMESPACE capability so using guessed prefix []
You can set the prefix namespace with the --prefix2 option,
the folowing listing of folders may help you to find it:
[Powiadomienia]
[Oferty]
[Spo&AUI-eczno&AVs-ci]
[Drafts]
[Junk]
[Sent]
[Trash]
[INBOX]
Host1: separator and prefix: [.][INBOX.]
Host2: separator and prefix: [/][]
Including all folders found by default. Use --subscribed or --folder or --folderrec or --include to select specific folders. Use --exclude to unselect specific folders.
Host1: Checking wanted folders exist. Use --nocheckfoldersexist to avoid this check (shared of public namespace targeted).
Host1: Checking wanted folders are selectable. Use --nocheckselectable to avoid this check.
Turned off automapping folders ( use --automap to turn on automapping )

++++ Listing folders
All foldernames are presented between brackets like [X] where X is the foldername.
When a foldername contains non-ASCII characters it is presented in the form
[X] = [Y] where
X is the imap foldername you have to use in command line options and
Y is the utf8 output just printed for convenience, to recognize it.

Host1: folders list (first the raw imap format then the [X] = [Y]):
* LIST (\HasChildren) "." INBOX
* LIST (\HasNoChildren) "." "INBOX.ESET Antispam"
* LIST (\HasNoChildren) "." INBOX.INBOX.Sent
* LIST (\HasNoChildren) "." INBOX.INBOX.Junk
* LIST (\HasNoChildren) "." INBOX.INBOX.Drafts
* LIST (\HasNoChildren) "." INBOX.INBOX.Trash
* LIST (\HasNoChildren) "." INBOX.Trash
* LIST (\HasNoChildren) "." INBOX.Wiadomo&AVs-ci-&AVs-mieci
* LIST (\HasNoChildren) "." "INBOX.Elementy wys&AUI-ane"
* LIST (\HasNoChildren) "." INBOX.Sent
* LIST (\HasNoChildren) "." "INBOX.Elementy usuni&ARk-te"
* LIST (\HasNoChildren) "." "INBOX.Wersje robocze"
* LIST (\HasNoChildren) "." "INBOX.Wykryte elementy"
22 OK List completed (0.000 + 0.000 secs).

[INBOX]
[INBOX.ESET Antispam]
[INBOX.Elementy usuni&ARk-te] = [INBOX.Elementy usunięte]
[INBOX.Elementy wys&AUI-ane] = [INBOX.Elementy wysłane]
[INBOX.INBOX.Drafts]
[INBOX.INBOX.Junk]
[INBOX.INBOX.Sent]
[INBOX.INBOX.Trash]
[INBOX.Sent]
[INBOX.Trash]
[INBOX.Wersje robocze]
[INBOX.Wiadomo&AVs-ci-&AVs-mieci] = [INBOX.Wiadomości-śmieci]
[INBOX.Wykryte elementy]

Host2: folders list (first the raw imap format then the [X] = [Y]):
* LIST (\NoInferiors) "/" Powiadomienia
* LIST (\NoInferiors) "/" Oferty
* LIST (\NoInferiors) "/" Spo&AUI-eczno&AVs-ci
* LIST (\NoInferiors) "/" Drafts
* LIST (\NoInferiors) "/" Junk
* LIST (\NoInferiors) "/" Sent
* LIST (\NoInferiors) "/" Trash
* LIST (\NoInferiors) "/" INBOX
9 OK List completed (0.001 + 0.000 secs).

[Drafts]
[INBOX]
[Junk]
[Oferty]
[Powiadomienia]
[Sent]
[Spo&AUI-eczno&AVs-ci] = [Społeczności]
[Trash]

Folders in host2 not in host1:
[Spo&AUI-eczno&AVs-ci] = [Społeczności]
[Powiadomienia]
[Oferty]
[Junk]
[Drafts]


Folders sizes before the synchronization.
You can remove foldersizes listings by using "--nofoldersizes" and "--nofoldersizesatend"
but then you will also lose the ETA (Estimation Time of Arrival) given after each message copy.
++++ Calculating sizes of 13 folders on Host1
Host1 folder    1/13 [INBOX]                             Size:     42026 Messages:     8 Biggest:      7928
Host1 folder    2/13 [INBOX.ESET Antispam]               Size:         0 Messages:     0 Biggest:         0
Host1 folder    3/13 [INBOX.Elementy usuni&ARk-te] = [INBOX.Elementy usunięte] Size:         0 Messages:     0 Biggest:         0
Host1 folder    4/13 [INBOX.Elementy wys&AUI-ane] = [INBOX.Elementy wysłane] Size:      3211 Messages:     1 Biggest:      3211
Host1 folder    5/13 [INBOX.INBOX.Drafts]                Size:         0 Messages:     0 Biggest:         0
Host1 folder    6/13 [INBOX.INBOX.Junk]                  Size:         0 Messages:     0 Biggest:         0
Host1 folder    7/13 [INBOX.INBOX.Sent]                  Size:       663 Messages:     1 Biggest:       663
Host1 folder    8/13 [INBOX.INBOX.Trash]                 Size:         0 Messages:     0 Biggest:         0
Host1 folder    9/13 [INBOX.Sent]                        Size:         0 Messages:     0 Biggest:         0
Host1 folder   10/13 [INBOX.Trash]                       Size:      5718 Messages:     1 Biggest:      5718
Host1 folder   11/13 [INBOX.Wersje robocze]              Size:         0 Messages:     0 Biggest:         0
Host1 folder   12/13 [INBOX.Wiadomo&AVs-ci-&AVs-mieci] = [INBOX.Wiadomości-śmieci] Size:         0 Messages:     0 Biggest:         0
Host1 folder   13/13 [INBOX.Wykryte elementy]            Size:         0 Messages:     0 Biggest:         0
Host1 Nb folders:               13 folders
Host1 Nb messages:              11 messages
Host1 Total size:            51618 bytes (50.408 KiB)
Host1 Biggest message:        7928 bytes (7.742 KiB)
Host1 Time spent:              3.7 seconds
++++ Calculating sizes of 13 folders on Host2
Host2 folder    1/13 [ESET Antispam]                     does not exist yet
Host2 folder    2/13 [Elementy usuni&ARk-te] = [Elementy usunięte] does not exist yet
Host2 folder    3/13 [Elementy wys&AUI-ane] = [Elementy wysłane] does not exist yet
Host2 folder    4/13 [INBOX]                             Size:    286065 Messages:     2 Biggest:    231514
Host2 folder    5/13 [INBOX/Drafts]                      does not exist yet
Host2 folder    6/13 [INBOX/Junk]                        does not exist yet
Host2 folder    7/13 [INBOX/Sent]                        does not exist yet
Host2 folder    8/13 [INBOX/Trash]                       does not exist yet
Host2 folder    9/13 [Sent]                              Size:         0 Messages:     0 Biggest:         0
Host2 folder   10/13 [Trash]                             Size:         0 Messages:     0 Biggest:         0
Host2 folder   11/13 [Wersje robocze]                    does not exist yet
Host2 folder   12/13 [Wiadomo&AVs-ci-&AVs-mieci] = [Wiadomości-śmieci] does not exist yet
Host2 folder   13/13 [Wykryte elementy]                  does not exist yet
Host2 Nb folders:               13 folders
Host2 Nb messages:               2 messages
Host2 Total size:           286065 bytes (279.360 KiB)
Host2 Biggest message:      231514 bytes (226.088 KiB)
Host2 Time spent:              0.1 seconds
++++ Looping on each one of 13 folders to sync
Folder    1/13 [INBOX]                             -> [INBOX]
Host1: folder [INBOX] has 8 messages in total (mentioned by SELECT)
Host2: folder [INBOX] has 2 messages in total (mentioned by SELECT)
Host2: folder [INBOX] permanentflags:
Host1: folder [INBOX] considering 8 messages
Host2: folder [INBOX] considering 2 messages
Host1: folder [INBOX] selected 8 messages, duplicates 0
Host2: INBOX/1 size 54569 ignored (no wanted headers so we ignore this message)
Host2: folder [INBOX] selected 2 messages, duplicates 0
msg INBOX/1 {6599}            copied to INBOX/3          1.00 msgs/s  6.444 KiB/s 6.444 KiB copied ETA: Thu Jul 23 08:12:48 2020  10 s  10/11 msgs left
msg INBOX/2 {4128}            copied to INBOX/4          2.00 msgs/s  10.476 KiB/s 10.476 KiB copied ETA: Thu Jul 23 08:12:42 2020  4 s  9/11 msgs left
msg INBOX/4 {4152}            copied to INBOX/5          3.00 msgs/s  14.530 KiB/s 14.530 KiB copied ETA: Thu Jul 23 08:12:41 2020  3 s  8/11 msgs left
msg INBOX/5 {4711}            copied to INBOX/6          3.87 msgs/s  18.503 KiB/s 19.131 KiB copied ETA: Thu Jul 23 08:12:40 2020  2 s  7/11 msgs left
msg INBOX/6 {5690}            copied to INBOX/7          4.22 msgs/s  20.858 KiB/s 24.688 KiB copied ETA: Thu Jul 23 08:12:40 2020  1 s  6/11 msgs left
msg INBOX/7 {3635}            copied to INBOX/8          4.42 msgs/s  20.812 KiB/s 28.237 KiB copied ETA: Thu Jul 23 08:12:40 2020  1 s  5/11 msgs left
msg INBOX/8 {7928}            copied to INBOX/9          4.65 msgs/s  23.916 KiB/s 35.979 KiB copied ETA: Thu Jul 23 08:12:39 2020  1 s  4/11 msgs left
msg INBOX/9 {5183}            copied to INBOX/10         4.81 msgs/s  24.685 KiB/s 41.041 KiB copied ETA: Thu Jul 23 08:12:39 2020  1 s  3/11 msgs left
Folder    2/13 [INBOX.ESET Antispam]               -> [ESET Antispam]
Host1: folder [INBOX.ESET Antispam] has 0 messages in total (mentioned by SELECT)
Creating folder [ESET Antispam] on host2
Created folder [ESET Antispam] on host2
Host2: folder [ESET Antispam] has 0 messages in total (mentioned by SELECT)
Host2: folder [ESET Antispam] permanentflags:
Host2: Subscribing to folder ESET Antispam
Host1: folder [INBOX.ESET Antispam] considering 0 messages
Host2: folder [ESET Antispam] considering 0 messages
Host1: folder [INBOX.ESET Antispam] selected 0 messages, duplicates 0
Host2: folder [ESET Antispam] selected 0 messages, duplicates 0
Folder    3/13 [INBOX.Elementy usuni&ARk-te] = [INBOX.Elementy usunięte] -> [Elementy usuni&ARk-te] = [Elementy usunięte]
Host1: folder [INBOX.Elementy usuni&ARk-te] has 0 messages in total (mentioned by SELECT)
Creating folder [Elementy usuni&ARk-te] on host2
Folder [Elementy usuni&ARk-te] already exists (--nomixfolders is not set)
Host2: folder [Elementy usuni&ARk-te] has 0 messages in total (mentioned by SELECT)
Host2: folder [Elementy usuni&ARk-te] permanentflags:
Host2: Subscribing to folder Elementy usuni&ARk-te
Host1: folder [INBOX.Elementy usuni&ARk-te] considering 0 messages
Host2: folder [Elementy usuni&ARk-te] considering 0 messages
Host1: folder [INBOX.Elementy usuni&ARk-te] selected 0 messages, duplicates 0
Host2: folder [Elementy usuni&ARk-te] selected 0 messages, duplicates 0
Folder    4/13 [INBOX.Elementy wys&AUI-ane] = [INBOX.Elementy wysłane] -> [Elementy wys&AUI-ane] = [Elementy wysłane]
Host1: folder [INBOX.Elementy wys&AUI-ane] has 1 messages in total (mentioned by SELECT)
Creating folder [Elementy wys&AUI-ane] on host2
Folder [Elementy wys&AUI-ane] already exists (--nomixfolders is not set)
Host2: folder [Elementy wys&AUI-ane] has 0 messages in total (mentioned by SELECT)
Host2: folder [Elementy wys&AUI-ane] permanentflags:
Host2: Subscribing to folder Elementy wys&AUI-ane
Host1: folder [INBOX.Elementy wys&AUI-ane] considering 1 messages
Host2: folder [Elementy wys&AUI-ane] considering 0 messages
Host1: folder [INBOX.Elementy wys&AUI-ane] selected 1 messages, duplicates 0
Host2: folder [Elementy wys&AUI-ane] selected 0 messages, duplicates 0
msg INBOX.Elementy wys&AUI-ane/1 {3211}            copied to Elementy wys&AUI-ane/1          3.55 msgs/s  17.422 KiB/s 44.177 KiB copied ETA: Thu Jul 23 08:12:40 2020  1 s  2/11 msgs left
Folder    5/13 [INBOX.INBOX.Drafts]                -> [INBOX/Drafts]
Host1: folder [INBOX.INBOX.Drafts] has 0 messages in total (mentioned by SELECT)
Creating folder [INBOX/Drafts] on host2
Created folder [INBOX/Drafts] on host2
Host2 folder INBOX/Drafts: Could not select: 54 NO Mailbox doesn't exist: INBOX/Drafts (0.003 + 0.000 + 0.002 secs).
Creating folder [INBOX/Drafts] on host2
Created folder [INBOX/Drafts] on host2
Host2 folder INBOX/Drafts: Could not select: 58 NO Mailbox doesn't exist: INBOX/Drafts (0.003 + 0.000 + 0.002 secs).
Folder    6/13 [INBOX.INBOX.Junk]                  -> [INBOX/Junk]
Host1: folder [INBOX.INBOX.Junk] has 0 messages in total (mentioned by SELECT)
Creating folder [INBOX/Junk] on host2
Created folder [INBOX/Junk] on host2
Host2 folder INBOX/Junk: Could not select: 62 NO Mailbox doesn't exist: INBOX/Junk (0.003 + 0.000 + 0.002 secs).
Creating folder [INBOX/Junk] on host2
Created folder [INBOX/Junk] on host2
Host2 folder INBOX/Junk: Could not select: 66 NO Mailbox doesn't exist: INBOX/Junk (0.002 + 0.000 + 0.001 secs).
Folder    7/13 [INBOX.INBOX.Sent]                  -> [INBOX/Sent]
Host1: folder [INBOX.INBOX.Sent] has 1 messages in total (mentioned by SELECT)
Creating folder [INBOX/Sent] on host2
Created folder [INBOX/Sent] on host2
Host2 folder INBOX/Sent: Could not select: 70 NO Mailbox doesn't exist: INBOX/Sent (0.002 + 0.000 + 0.001 secs).
Creating folder [INBOX/Sent] on host2
Created folder [INBOX/Sent] on host2
Host2 folder INBOX/Sent: Could not select: 74 NO Mailbox doesn't exist: INBOX/Sent (0.002 + 0.000 + 0.001 secs).
Folder    8/13 [INBOX.INBOX.Trash]                 -> [INBOX/Trash]
Host1: folder [INBOX.INBOX.Trash] has 0 messages in total (mentioned by SELECT)
Creating folder [INBOX/Trash] on host2
Created folder [INBOX/Trash] on host2
Host2 folder INBOX/Trash: Could not select: 78 NO Mailbox doesn't exist: INBOX/Trash (0.002 + 0.000 + 0.001 secs).
Creating folder [INBOX/Trash] on host2
Created folder [INBOX/Trash] on host2
Host2 folder INBOX/Trash: Could not select: 82 NO Mailbox doesn't exist: INBOX/Trash (0.002 + 0.000 + 0.001 secs).
Folder    9/13 [INBOX.Sent]                        -> [Sent]
Host1: folder [INBOX.Sent] has 0 messages in total (mentioned by SELECT)
Host2: folder [Sent] has 1 messages in total (mentioned by SELECT)
Host2: folder [Sent] permanentflags:
Host1: folder [INBOX.Sent] considering 0 messages
Host2: folder [Sent] considering 1 messages
Host1: folder [INBOX.Sent] selected 0 messages, duplicates 0
Host2: folder [Sent] selected 1 messages, duplicates 0
Folder   10/13 [INBOX.Trash]                       -> [Trash]
Host1: folder [INBOX.Trash] has 1 messages in total (mentioned by SELECT)
Host2: folder [Trash] has 0 messages in total (mentioned by SELECT)
Host2: folder [Trash] permanentflags:
Host1: folder [INBOX.Trash] considering 1 messages
Host2: folder [Trash] considering 0 messages
Host1: folder [INBOX.Trash] selected 1 messages, duplicates 0
Host2: folder [Trash] selected 0 messages, duplicates 0
msg INBOX.Trash/1 {5718}            copied to Trash/1          2.53 msgs/s  12.601 KiB/s 49.761 KiB copied ETA: Thu Jul 23 08:12:41 2020  0 s  1/11 msgs left
Folder   11/13 [INBOX.Wersje robocze]              -> [Wersje robocze]
Host1: folder [INBOX.Wersje robocze] has 0 messages in total (mentioned by SELECT)
Creating folder [Wersje robocze] on host2
Created folder [Wersje robocze] on host2
Host2: folder [Wersje robocze] has 0 messages in total (mentioned by SELECT)
Host2: folder [Wersje robocze] permanentflags:
Host2: Subscribing to folder Wersje robocze
Host1: folder [INBOX.Wersje robocze] considering 0 messages
Host2: folder [Wersje robocze] considering 0 messages
Host1: folder [INBOX.Wersje robocze] selected 0 messages, duplicates 0
Host2: folder [Wersje robocze] selected 0 messages, duplicates 0
Folder   12/13 [INBOX.Wiadomo&AVs-ci-&AVs-mieci] = [INBOX.Wiadomości-śmieci] -> [Wiadomo&AVs-ci-&AVs-mieci] = [Wiadomości-śmieci]
Host1: folder [INBOX.Wiadomo&AVs-ci-&AVs-mieci] has 0 messages in total (mentioned by SELECT)
Creating folder [Wiadomo&AVs-ci-&AVs-mieci] on host2
Folder [Wiadomo&AVs-ci-&AVs-mieci] already exists (--nomixfolders is not set)
Host2: folder [Wiadomo&AVs-ci-&AVs-mieci] has 0 messages in total (mentioned by SELECT)
Host2: folder [Wiadomo&AVs-ci-&AVs-mieci] permanentflags:
Host2: Subscribing to folder Wiadomo&AVs-ci-&AVs-mieci
Host1: folder [INBOX.Wiadomo&AVs-ci-&AVs-mieci] considering 0 messages
Host2: folder [Wiadomo&AVs-ci-&AVs-mieci] considering 0 messages
Host1: folder [INBOX.Wiadomo&AVs-ci-&AVs-mieci] selected 0 messages, duplicates 0
Host2: folder [Wiadomo&AVs-ci-&AVs-mieci] selected 0 messages, duplicates 0
Folder   13/13 [INBOX.Wykryte elementy]            -> [Wykryte elementy]
Host1: folder [INBOX.Wykryte elementy] has 0 messages in total (mentioned by SELECT)
Creating folder [Wykryte elementy] on host2
Created folder [Wykryte elementy] on host2
Host2: folder [Wykryte elementy] has 0 messages in total (mentioned by SELECT)
Host2: folder [Wykryte elementy] permanentflags:
Host2: Subscribing to folder Wykryte elementy
Host1: folder [INBOX.Wykryte elementy] considering 0 messages
Host2: folder [Wykryte elementy] considering 0 messages
Host1: folder [INBOX.Wykryte elementy] selected 0 messages, duplicates 0
Host2: folder [Wykryte elementy] selected 0 messages, duplicates 0
++++ End looping on each folder

Folders sizes after the synchronization.
You can remove this foldersizes listing by using  "--nofoldersizesatend"
++++ Calculating sizes of 13 folders on Host1
Host1 folder    1/13 [INBOX]                             Size:     42026 Messages:     8 Biggest:      7928
Host1 folder    2/13 [INBOX.ESET Antispam]               Size:         0 Messages:     0 Biggest:         0
Host1 folder    3/13 [INBOX.Elementy usuni&ARk-te] = [INBOX.Elementy usunięte] Size:         0 Messages:     0 Biggest:         0
Host1 folder    4/13 [INBOX.Elementy wys&AUI-ane] = [INBOX.Elementy wysłane] Size:      3211 Messages:     1 Biggest:      3211
Host1 folder    5/13 [INBOX.INBOX.Drafts]                Size:         0 Messages:     0 Biggest:         0
Host1 folder    6/13 [INBOX.INBOX.Junk]                  Size:         0 Messages:     0 Biggest:         0
Host1 folder    7/13 [INBOX.INBOX.Sent]                  Size:       663 Messages:     1 Biggest:       663
Host1 folder    8/13 [INBOX.INBOX.Trash]                 Size:         0 Messages:     0 Biggest:         0
Host1 folder    9/13 [INBOX.Sent]                        Size:         0 Messages:     0 Biggest:         0
Host1 folder   10/13 [INBOX.Trash]                       Size:      5718 Messages:     1 Biggest:      5718
Host1 folder   11/13 [INBOX.Wersje robocze]              Size:         0 Messages:     0 Biggest:         0
Host1 folder   12/13 [INBOX.Wiadomo&AVs-ci-&AVs-mieci] = [INBOX.Wiadomości-śmieci] Size:         0 Messages:     0 Biggest:         0
Host1 folder   13/13 [INBOX.Wykryte elementy]            Size:         0 Messages:     0 Biggest:         0
Host1 Nb folders:               13 folders
Host1 Nb messages:              11 messages
Host1 Total size:            51618 bytes (50.408 KiB)
Host1 Biggest message:        7928 bytes (7.742 KiB)
Host1 Time spent:              1.5 seconds
++++ Calculating sizes of 13 folders on Host2
Host2 folder    1/13 [ESET Antispam]                     Size:         0 Messages:     0 Biggest:         0
Host2 folder    2/13 [Elementy usuni&ARk-te] = [Elementy usunięte] does not exist yet
Host2 folder    3/13 [Elementy wys&AUI-ane] = [Elementy wysłane] does not exist yet
Host2 folder    4/13 [INBOX]                             Size:    328475 Messages:    10 Biggest:    231514
Host2 folder    5/13 [INBOX/Drafts]                      does not exist yet
Host2 folder    6/13 [INBOX/Junk]                        does not exist yet
Host2 folder    7/13 [INBOX/Sent]                        does not exist yet
Host2 folder    8/13 [INBOX/Trash]                       does not exist yet
Host2 folder    9/13 [Sent]                              Size:      3259 Messages:     1 Biggest:      3259
Host2 folder   10/13 [Trash]                             Size:      5766 Messages:     1 Biggest:      5766
Host2 folder   11/13 [Wersje robocze]                    Size:         0 Messages:     0 Biggest:         0
Host2 folder   12/13 [Wiadomo&AVs-ci-&AVs-mieci] = [Wiadomości-śmieci] does not exist yet
Host2 folder   13/13 [Wykryte elementy]                  Size:         0 Messages:     0 Biggest:         0
Host2 Nb folders:               13 folders
Host2 Nb messages:              12 messages
Host2 Total size:           337500 bytes (329.590 KiB)
Host2 Biggest message:      231514 bytes (226.088 KiB)
Host2 Time spent:              0.2 seconds
++++ Statistics
Transfer started on                     : Thu Jul 23 08:12:33 2020
Transfer ended on                       : Thu Jul 23 08:12:43 2020
Transfer time                           : 10.1 sec
Folders synced                          : 13/13 synced
Messages transferred                    : 10
Messages skipped                        : 0
Messages found duplicate on host1       : 0
Messages found duplicate on host2       : 0
Messages found crossduplicate on host2  : 0
Messages void (noheader) on host1       : 0
Messages void (noheader) on host2       : 1
Messages found in host1 not in host2    : 0 messages
Messages found in host2 not in host1    : 1 messages
Messages deleted on host1               : 0
Messages deleted on host2               : 0
Total bytes transferred                 : 50955 (49.761 KiB)
Total bytes skipped                     : 0 (0.000 KiB)
Message rate                            : 1.0 messages/s
Average bandwidth rate                  : 4.9 KiB/s
Reconnections to host1                  : 0
Reconnections to host2                  : 0
Memory consumption at the end           : 188.4 MiB (started with 170.5 MiB)
Load end is                             : 0.52 0.58 0.59 1/5 on 16 cores
Biggest message                         : 7928 bytes (7.742 KiB)
Memory/biggest message ratio            : 24916.5
Start difference host2 - host1          : -9 messages, 234447 bytes (228.952 KiB)
Final difference host2 - host1          : 1 messages, 285882 bytes (279.182 KiB)
The sync looks good, all 10 identified messages in host1 are on host2.
The sync is not strict, there are 1 messages in host2 that are not on host1. Use --delete2 to delete them and have a strict sync.
Detected 8 errors

Check if a new imapsync release is available by adding --releasecheck
Homepage: https://imapsync.lamiral.info/
++++ Listing 8 errors encountered during the sync ( avoid this listing with --noerrorsdump ).
Err 1/8: Host2 folder INBOX/Drafts: Could not select: 54 NO Mailbox doesn't exist: INBOX/Drafts (0.003 + 0.000 + 0.002 secs).
Err 2/8: Host2 folder INBOX/Drafts: Could not select: 58 NO Mailbox doesn't exist: INBOX/Drafts (0.003 + 0.000 + 0.002 secs).
Err 3/8: Host2 folder INBOX/Junk: Could not select: 62 NO Mailbox doesn't exist: INBOX/Junk (0.003 + 0.000 + 0.002 secs).
Err 4/8: Host2 folder INBOX/Junk: Could not select: 66 NO Mailbox doesn't exist: INBOX/Junk (0.002 + 0.000 + 0.001 secs).
Err 5/8: Host2 folder INBOX/Sent: Could not select: 70 NO Mailbox doesn't exist: INBOX/Sent (0.002 + 0.000 + 0.001 secs).
Err 6/8: Host2 folder INBOX/Sent: Could not select: 74 NO Mailbox doesn't exist: INBOX/Sent (0.002 + 0.000 + 0.001 secs).
Err 7/8: Host2 folder INBOX/Trash: Could not select: 78 NO Mailbox doesn't exist: INBOX/Trash (0.002 + 0.000 + 0.001 secs).
Err 8/8: Host2 folder INBOX/Trash: Could not select: 82 NO Mailbox doesn't exist: INBOX/Trash (0.002 + 0.000 + 0.001 secs).
Exiting with return value 111 (EXIT_WITH_ERRORS)
Log file is LOG_imapsync/2020_07_23_08_12_33_744_test@test.com_test@onet.pl.txt ( to change it, use --logfile filepath ; or use --nolog to turn off logging )

Nie znalazłem rozwiązania na błędy, które pojawiają się na samym końcu, więc jeśli ktoś zna rozwiązanie – chętnie o tym posłucham.

Exchange i przenoszenie wielu skrzynek na inny serwer

Tutaj sprawa jest nieco skomplikowana: Exchange domyślnie nie obsługuje IMAPa, to znaczy ta funkcja jest wyłączona. Trzeba ją włączyć i skonfigurować dla użytkowników. Jeśli chodzi o synchronizację wielu użytkowników – niczym się nie różni w stosunku tego, co jest powyżej, poza tym, że robimy to dla wielu użytkowników i czytamy loginy i hasła kont źródłowych i docelowych z pliku CSV. Testy robiłem na Exchange 2019 i do niego będę się odnosił. Nazwa serwera mailowego to mail.serba.website. Poza tym, co wspomniałem, konta muszą być wcześniej utworzone na docelowym serwerze, na który przenosimy skrzynki.

Instrukcja włączania IMAPa jest tutaj, ale ja ją skrócę – poniższe usługi trzeba włączyć i zmienić ich tryb na Automatyczny:

Następnie należy ustawić adres FQDN dla serwera IMAP Exchange’a:

C:\Windows\system32>Set-ImapSettings -ExternalConnectionSettings "mail.serba.website:993:SSL","mail.serba.website:143:TLS" -X509CertificateName mail.serba.website
WARNING: Changes to IMAP4 settings will only take effect after all Microsoft Exchange IMAP4 services are restarted on server EXCHANGE.

Po tym należy wykonać restart usługi:

[PS] C:\Windows\system32>Restart-Service MSExchangeIMAP4; Restart-Service MSExchangeIMAP4BE
WARNING: Waiting for service 'Microsoft Exchange IMAP4 (MSExchangeIMAP4)' to start...
WARNING: Waiting for service 'Microsoft Exchange IMAP4 (MSExchangeIMAP4)' to start...
WARNING: Waiting for service 'Microsoft Exchange IMAP4 Backend (MSExchangeIMAP4BE)' to start...
WARNING: Waiting for service 'Microsoft Exchange IMAP4 Backend (MSExchangeIMAP4BE)' to start...
[PS] C:\Windows\system32>Get-Service MSExchangeIMAP4; Get-Service MSExchangeIMAP4BE

Status   Name               DisplayName
------   ----               -----------
Running  MSExchangeIMAP4    Microsoft Exchange IMAP4
Running  MSExchangeIMAP4BE  Microsoft Exchange IMAP4 Backend

Po tym IMAP działa, ale nie można zapomnieć o tym, by ten miał ważny certyfikat SSL lub jeśli ma samopodpisany lub nieważny, należy użyć opcji --sslargs2 SSL_verify_mode=0 zakładając, że Exchange jest serwerem na który przenosimy skrzynki.

Następnie należy przygotować skrypt, który wykona nam synchronizację oraz plik CSV zawierający loginy i hasła. CSV wygląda tak (zapisany jako konta.csv):

konto1@test.com;haslo1;apilecki@website;haslo1
konto2@test.com;haslo2;bpoprawa@website;haslo2
konto3@test.com;haslo3;fkluk@website;haslo3

Skrypt wygląda tak:

{ while IFS=';' read  u1 p1 u2 p2; do
/mnt/c/Users/Administrator.SERBA/Desktop/imapsync/imapsync --host1 ssl0.ovh.net --user1 "$u1" --password1 "$p1" --ssl1 --port1 993 \
                             --host2 exchange.serba.local --user2 "$u2" --password2 "$p2" -ssl2
                         done ; } < konta.csv

Oczywiście należy podmienić ścieżkę do imapsync na właściwą wcześniej, po tym zapisujemy skrypt jako sync.sh i wykonujemy polecenie bash sync.sh. Po tym skrzynki się zsynchronizują.

Kwestie wydajnościowe

Według zaleceń twórcy IMAPsynca są kwestie, które trzeba wziąć pod uwagę pod kątem synchronizacji i myślę, przy masowych synchronizacjach warto wziąć pod uwagę. Jeśli mamy dużo kont do synchronizacji to można podzielić plik CSV na mniejsze i odpalić osobne procesy dla każdego pliku CSV – w ten sposób więcej synchronizacji można wykonać w jednym czasie, lecz nie ma dokładnego określenia ile ich ma być. Pozostaje testować. Poza tym, warto takie synchronizacje robić z poziomu źródłowego serwera pocztowego lub z docelowego serwera pocztowego (jeśli to jest w ogóle możliwe). To zapewni nam najlepszą wydajność, na przykład jeśli wysyłamy skrzynkę do Office 365 z lokalnego Exchange, warto taki program odpalić bezpośrednio na Exchange’u (jeśli to w ogóle możliwe),

Ustawienie domyślnego startu ze starszej wersji kernela Linux w GRUB

Przeczytasz to w: 4 minut

Domyślnie GRUB startuje z 0, czyli wpisu, który jest na samej górze listy. To może być problematyczne, jeśli nasz system się od czasu do czasu aktualizuje, a my z powodu jakiejś aplikacji nie możemy się przenieść na nowszą wersję, na przykład aktualnie Docker nie obsługuje kerneli 5.x, a 4.x owszem. By pozbyć się problemu należy:

  • zawsze odpalać system z tego samego wpisu w GRUB,
  • zapobiec usunięciu starego kernela z systemu.

To pierwsze można osiągnąć poprzez edycję pliku /etc/default/grub. Często nie mamy dostępu do KVMa lub dostęp do niego na serwerach zabiera nam cenny czas, więc możemy sobie wygenerować szybko listę wpisów takim one-linerem:

sed -nre "/submenu|menuentry/s/(.? )'([^']+)'.*/\1 \2/p" < /boot/grub/grub.cfg
menuentry  Ubuntu
submenu  Advanced options for Ubuntu
        menuentry  Ubuntu, with Linux 5.4.0-37-generic
        menuentry  Ubuntu, with Linux 5.4.0-37-generic (recovery mode)
        menuentry  Ubuntu, with Linux 5.4.0-33-generic
        menuentry  Ubuntu, with Linux 5.4.0-33-generic (recovery mode)
        menuentry  Ubuntu, with Linux 4.10.0-42-generic //z tego chcę odpalać system
        menuentry  Ubuntu, with Linux 4.10.0-42-generic (recovery mode)

W takiej sytuacji w /etc/default/grub w zmiennej GRUB_DEFAULT wpisuję wartość:

# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 4.10.0-42-generic"
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""
GRUB_RECORDFAIL_TIMEOUT=0
# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
GRUB_GFXMODE=1600x900

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

Potem wystarczy wykonać sudo update-grub i gotowe. Jeśli nie chce się Wam grzebać w konsoli to jest aplikacja okienkowa, która też robi robotę. Teraz upewnijmy się, że nasz kernel nie zostanie usunięty z systemu. Na początku musimy się zorientować jaka jest nasza wersja kernela (jeśli tego nie widzieliśmy wyżej):

dpkg -l | grep linux-image
ii  linux-image-4.10.0-42-generic         4.10.0-42.46~16.04.1                        amd64        Linux kernel image for version 4.10.0 on 64 bit x86 SMP
rc  linux-image-4.15.0-36-generic         4.15.0-36.39                                amd64        Signed kernel image generic
rc  linux-image-4.15.0-38-generic         4.15.0-38.41                                amd64        Signed kernel image generic
rc  linux-image-4.15.0-39-generic         4.15.0-39.42                                amd64        Signed kernel image generic
rc  linux-image-4.18.0-13-generic         4.18.0-13.14                                amd64        Signed kernel image generic
rc  linux-image-4.18.0-14-generic         4.18.0-14.15                                amd64        Signed kernel image generic
rc  linux-image-4.18.0-15-generic         4.18.0-15.16                                amd64        Signed kernel image generic
ii  linux-image-4.4.0-112-generic         4.4.0-112.135                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-116-generic         4.4.0-116.140                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-119-generic         4.4.0-119.143                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-121-generic         4.4.0-121.145                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-122-generic         4.4.0-122.146                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-124-generic         4.4.0-124.148                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-127-generic         4.4.0-127.153                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-128-generic         4.4.0-128.154                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-130-generic         4.4.0-130.156                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-131-generic         4.4.0-131.157                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-133-generic         4.4.0-133.159                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-134-generic         4.4.0-134.160                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-135-generic         4.4.0-135.161                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-4.4.0-137-generic         4.4.0-137.163                               amd64        Linux kernel image for version 4.4.0 on 64 bit x86 SMP
rc  linux-image-5.0.0-13-generic          5.0.0-13.14                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-15-generic          5.0.0-15.16                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-16-generic          5.0.0-16.17                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-17-generic          5.0.0-17.18                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-19-generic          5.0.0-19.20                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-20-generic          5.0.0-20.21                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-21-generic          5.0.0-21.22                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-23-generic          5.0.0-23.24                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-25-generic          5.0.0-25.26                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-27-generic          5.0.0-27.28                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-29-generic          5.0.0-29.31                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-31-generic          5.0.0-31.33                                 amd64        Signed kernel image generic
rc  linux-image-5.0.0-32-generic          5.0.0-32.34                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-19-generic          5.3.0-19.20                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-22-generic          5.3.0-22.24                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-23-generic          5.3.0-23.25                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-24-generic          5.3.0-24.26                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-26-generic          5.3.0-26.28                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-29-generic          5.3.0-29.31                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-40-generic          5.3.0-40.32                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-42-generic          5.3.0-42.34                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-45-generic          5.3.0-45.37                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-46-generic          5.3.0-46.38                                 amd64        Signed kernel image generic
rc  linux-image-5.3.0-51-generic          5.3.0-51.44                                 amd64        Signed kernel image generic
rc  linux-image-5.4.0-29-generic          5.4.0-29.33                                 amd64        Signed kernel image generic
rc  linux-image-5.4.0-31-generic          5.4.0-31.35                                 amd64        Signed kernel image generic
ii  linux-image-5.4.0-33-generic          5.4.0-33.37                                 amd64        Signed kernel image generic
ii  linux-image-5.4.0-37-generic          5.4.0-37.41                                 amd64        Signed kernel image generic
ii  linux-image-extra-4.10.0-42-generic   4.10.0-42.46~16.04.1                        amd64        Linux kernel extra modules for version 4.10.0 on 64 bit x86 SMP
ii  linux-image-generic                   5.4.0.37.40                                 amd64        Generic Linux kernel image
ii  linux-image-virtual                   5.4.0.37.40                                 amd64        Virtual Linux kernel image

Zaznaczone paczki należy zablokować przed usunięciem i robimy to z poziomu roota:

echo linux-image-4.10.0-42-generic hold | dpkg --set-selections;
echo linux-image-generic hold | dpkg --set-selections;
echo linux-image-extra-4.10.0-42-generic hold | dpkg --set-selections;

I to tyle. Teraz apt ich nie usunie przy aktualizacji.

Szybkie tworzenie klucza, CSRek oraz konwersja certyfikatów w OpenSSL

Przeczytasz to w: < 1 minutę

Tworzenie klucza RSA 2048-bitowego:

openssl genrsa –out klucz.key 2048 //nie działa w powershell, tam trzeba podać pełną ścieżkę pliku

Następnie, aby stworzyć CSRkę (certificate signing request) warto mieć do tego przygotowany config. Przykładowy wygląda tak:

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C=PL
ST=SL
L=Tychy
O=it.supra.tf
OU=IT
emailAddress=radoslaw@serba.ovh
CN = it.supra.tf

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = it.supra.tf

Takie coś zapisujemy do jakiegoś pliku, np. config.cnf.
Następnie tworzymy CSR:

openssl req -new -sha256 -key klucz.key -out it.supra.tf.csr -config config.cnf

Potem taki CSR musimy wykorzystać do podpisania certyfikatu w naszym CA. Jeśli pobierzemy plik w formacie DER zamiast Base-64, można go skonwertować w ten sposób:

openssl x509 -inform pem -in it.supra.tf.cer -out it.supra.tf.pem

Przy okazji te polecenie się przydaje do sprawdzenia zawartości CSRki:

openssl req -in shadowcontrol.anzenalab.local.csr -text -noout

iRedMail, LDAP i migracja serwera pocztowego, z której się sporo nauczyłem

Przeczytasz to w: 16 minut

Ten post nie będzie do końca taki, jak wcześniej, bo niestety nie mam tyle czasu, by opisać całą instalację iRedMaila i tego, co robiłem. Ogólnie udało mi się zmigrować u klienta serwer pocztowy. Klient miał Debiana 6, trochę stary, użytkownicy lokalni, a nie w SQLu czy LDAPie (OpenLDAP lub AD) i trzeba było coś z tym zrobić. Był to jakiś pakiet, który bazował na Postfixie/Dovecot z interfejsem webowym Squirrel. Trzeba było coś z tym zrobić, więc ostatecznie zdecydowaliśmy się na migrację serwera na nowy, z Debianem 10 i celem był iRedMail – prosty pakiet z Postfixem i Dovecotem z podstawowym panelem administracyjnym. Wdrożyłem go z LDAPem z prostego powodu: jest szansa na to, że w przyszłości taki użytkownik będzie mógł wykorzystać logowanie z Active Directory jeśli przepnie się query z LDAPa do AD oraz każdemu użytkownikowi w AD doda się odpowiedni atrybuty, z których korzysta iRedMail.

Dlatego też jeśli chcecie się nauczyć stawiać iRedMaila – polecam sobie poczytać ich dokumentację. Jest tam naprawdę sporo ciekawych materiałów. Pomimo to są rzeczy, które nawet jeśli są w tej dokumentacji przykuły moją uwagę.

Migracja użytkowników do OpenLDAPa

Użytkownicy byli przechowywani lokalnie, więc mogłem znaleźć ich nazwy użytkowników, nazwy wyświetlane (Gecos) itd w pliku /etc/passwd. Ogólnie ten plik wygląda tak:

root:$6$somesalt$aaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbb/cccccccccccccccccc/ddddddddddd.eeeeee
supra:$6$somesalt$aaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbb/cccccccccccccccccc/ddddddddddd.eeeeeeeeeeee/:17604:0:99999:7:::
anotheruser:$6$somesalt$aaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbb/cccccccccccccccccc/ddddddddddd.eeeeeeeeeeee.:17604:0:99999:7:::
editor:$6$somesalt$aaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbb/cccccccccccccccccc/ddddddddddd.eeeeeeeeeeee.:17668:0:99999:7:::
test:$6$somesalt$aaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbb/cccccccccccccccccc/ddddddddddd.eeeeeeeeeeee.:18314:0:99999:7:::

Tutaj znalazłem informację jak tworzyć użytkowników w LDAPie z odpowiednimi atrybutami. Z tego pliku wyciągnęliśmy listę wszystkich użytkowników oraz Gecos. Wystarczy do tego Excel lub inny program pracujący z arkuszami kalkulacyjnymi, który jest w stanie zczytywać dane z plików, które mają oddzielone wartości za pomocą jakiegoś znaku (np. CSV). Na początku klikamy Z pliku tekstowego/CSV, następnie wskazujemy plik i wybieramy ogranicznik (znak oddzielający wartości, ang. delimiter), powinien być nim dwukropek.

Korzystam z Excel 2019 i on sam wykrył ten znak (musiałem jedynie zmienić kodowanie pliku na UTF-8), zmieniłem też pole Wykrywanie typu danych na Nie wykrywaj typów danych:

Jak widać, wszystko ładnie się zaimportowało:

Następnie należy trochę przerobić te dane. Składnia to:

mydomain.com, user2, plain_password, Michael Jordan, group1:group2,

W praktyce to powinno wyglądać tak:

Jak widać w stosunku do zrzutu ekranu wyżej, usunąłem przecinki po w nazwie wyświetlanej oraz poprzenosiłem wartości w kolejności. Kolumna F jest pusta, bo nie mam zdefiniowanych żadnych grup. W takiej sytuacji trzeba na końcu każdej linii po wyeksportowaniu pliku CSV dopisać spację i przecinek. Dodałem też te liczby i 5368709120 to jest quota (przydział rozmiaru skrzynki) w bajtach. 5368709120 daje nam 5 GB.

Zapisujemy plik w postaci CSV UTF-8 (w ogóle to jest dostępne tylko w Excel 2019, nie wiedzieć czemu):

Otrzymujemy to (otwieram takie pliki w Visual Studio Code):

Podmieńmy sobie najpierw średniki ; na przecinki ze spacją , :

Teraz musimy jakoś dodać te puste pola grup. Z faktu, że przypisałem wszystkim użytkownikom taką samą wielkość skrzynki, wykorzystam to, by dodać dodatkową wartość:

W ten sposób możemy wykorzystać taki plik CSV do zaimportowania użytkowników. Jak widać, nie przenoszę tutaj haseł tylko generuję nowe. Skorzystałem z random.org do wygenerowania hasełek, które wkleiłem do arkusza:

iRedMail dostarcza skrypty, które przygotowują za nas plik LDIF, który potem musimy wykorzystać do dodania użytkowników za pomocą polecenia ldapadd. Powinny być w folderze instalacyjnym iRedMaila, w folderze tools. Są dwa skrypty: create_mail_user_OpenLDAP.py i create_mail_user_OpenLDAP.sh. Ja skorzystałem z tego pierwszego, bo we wdrożeniu chciałem mieć katalogi użytkowników w konkretnym katalogu, a ten bashowy skrypt chyba na to nie pozwalał.

To, co trzeba sobie w tym skrypcie zmienić to:

# LDAP server address.
LDAP_URI = 'ldap://127.0.0.1:389'

# LDAP base dn.
BASEDN = 'o=domains,dc=example,dc=com'

# Bind dn/password
BINDDN = 'cn=Manager,dc=example,dc=com'
BINDPW = 'supersecretpassword'

# Storage base directory.
STORAGE_BASE_DIRECTORY = '/var/vmail/vmail1'

# Append timestamp in maildir path.
APPEND_TIMESTAMP_IN_MAILDIR = True

# Get base directory and storage node.
std = STORAGE_BASE_DIRECTORY.rstrip('/').split('/')
STORAGE_NODE = std.pop()
STORAGE_BASE = '/'.join(std)

# Hashed maildir: True, False.
# Example:
#   domain: domain.ltd,
#   user:   zhang (zhang@domain.ltd)
#
#       - hashed: d/do/domain.ltd/z/zh/zha/zhang/
#       - normal: domain.ltd/zhang/
HASHED_MAILDIR = True

Te zmienne definiują:

  • LDAP_URI – adres serwera LDAP, do którego się łączymy (jest on na serwerze localnie),
  • BASEDN – DN domeny, każdy element oddziela się przecinkiem w miejscu, gdzie jest kropka w nazwie, np. super.domena.com dzieli się na dc=super,dc=domena,dc=com, dopisujemy na początku o=domains wyjątkowo w tym polu,
  • BINDDN – użytkownik, na prawach którego wykonujemy operację, przy czym Manager jest kontem, które ma pełne prawa do modyfikowania wszystkiego, co jest w LDAPie, w dużym uproszczeniu to jest nazwa użytkownika + nazwa domeny, którą przedstawiałem wyżej, w tym polu trzeba poprawić domenę
  • BINDPW – hasło do konta Manager, znajdziemy je w katalogu instalacyjnym w pliku iRedMail.tips,
  • STORAGE_BASE_DIRECTORY – katalog bazowy, w którym znajdują się wszystkie skrzynki, ścieżka do katalogu użytkownika to STORAGE_BASE_DIRECTORY/<domena>/<folder-użytkownika>
  • APPEND_TIMESTAMP_IN_MAILDIR – jeśli true, foldery użytkownika wyglądają tak: supra-2020.04.22.17.19.56
  • HASHED_MAILDIR – tutaj ładnie jest opisane w skrypcie, w praktyce jak mamy włączony hash z ścieżką katalogu bazowego jak w skrypcie oraz dopisanie daty do nazwy folderu użytkownika to pełna ścieżka do skrzynki mailowej przykładowego użytkownika supra wygląda tak: /var/vmail/vmail1/domain.com/s/u/p/supra-2020.04.22.17.19.56

Jak mamy to, możemy sobie wrzucić plik CSV na serwer i go po prostu zaimportować. Warto sobie sprawdzić czy nazwy wyświetlane dobrze nam się czytają, by nie mieć żadnych znaków z niespodzianką (np. moje imię ma znak, który jest polski):

Jak widać, wszystko działa.

Jak to jest wszystko okej, odpalamy skrypt:

sudo python create_mail_user_OpenLDAP.py /home/supra/import.csv

Z jakiegoś powodu otrzymywałem ten błąd:

Traceback (most recent call last):
  File "create_mail_user_OpenLDAP.py", line 303, in <module>
    ldif_writer.unparse(dn, data)
  File "/usr/lib/python2.7/dist-packages/ldif.py", line 194, in unparse
    dn = dn.encode('utf-8')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 11: ordinal not in range(128)

Żeby rozwiązać to, należy wykorzystać program dos2unix, by przekonwertować plik:

$ dos2unix import.csv
dos2unix: konwersja pliku import.csv do formatu uniksowego...

Ewentualnie to można zrobić w Vimie poleceniem :set nobomb i zapisując plik. Teraz wynik dostaję taki:

< INFO > User data are stored in /home/supra/import.csv.ldif, you can verify it before importing it.
< INFO > You can import it with below command:
ldapadd -x -D cn=Manager,dc=example,dc=com -W -f /home/supra/import.csv.ldif

Plik wygląda tak:

dn: mail=supra@mydomain.com,ou=Users,domainName=mydomain.com,o=domains,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: mailUser
objectClass: shadowAccount
objectClass: amavisAccount
mail: supra@mydomain.com
userPassword: {SSHA}wDV2pLwacxHOT8GpMRL3+wta9PfGGmVp
mailQuota: 5368709120
cn:: UmFkb3PFgmF3IFNlcmJh
sn: supra
uid: supra
storageBaseDirectory: /var/vmail
mailMessageStore: vmail1/mydomain.com/s/u/p/supra-2020.05.16.20.20.07/
homeDirectory: /var/vmail/vmail1/mydomain.com/s/u/p/supra-2020.05.16.20.20.07/
accountStatus: active
enabledService: internal
enabledService: doveadm
enabledService: lib-storage
enabledService: indexer-worker
enabledService: dsync
enabledService: quota-status
enabledService: mail
enabledService: smtp
enabledService: smtpsecured
enabledService: smtptls
enabledService: pop3
enabledService: pop3secured
enabledService: pop3tls
enabledService: imap
enabledService: imapsecured
enabledService: imaptls
enabledService: deliver
enabledService: lda
enabledService: forward
enabledService: senderbcc
enabledService: recipientbcc
enabledService: managesieve
enabledService: managesievesecured
enabledService: sieve
enabledService: sievesecured
enabledService: lmtp
enabledService: sogo
enabledService: shadowaddress
enabledService: displayedInGlobalAddressBook
shadowLastChange: 18398
amavisLocal: TRUE

dn: mail=mmarecki@mydomain.com,ou=Users,domainName=mydomain.com,o=domains,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: mailUser
objectClass: shadowAccount
objectClass: amavisAccount
mail: mmarecki@mydomain.com
userPassword: {SSHA}L+5CB3x3tUyilp90aF9FFa9/Rab5FqAo
mailQuota: 5368709120
cn: Marek Marecki
sn: mmarecki
uid: mmarecki
storageBaseDirectory: /var/vmail
mailMessageStore: vmail1/mydomain.com/m/m/a/mmarecki-2020.05.16.20.20.07/
homeDirectory: /var/vmail/vmail1/mydomain.com/m/m/a/mmarecki-2020.05.16.20.20.07/
accountStatus: active
enabledService: internal
enabledService: doveadm
enabledService: lib-storage
enabledService: indexer-worker
enabledService: dsync
enabledService: quota-status
enabledService: mail
enabledService: smtp
enabledService: smtpsecured
enabledService: smtptls
enabledService: pop3
enabledService: pop3secured
enabledService: pop3tls
enabledService: imap
enabledService: imapsecured
enabledService: imaptls
enabledService: deliver
enabledService: lda
enabledService: forward
enabledService: senderbcc
enabledService: recipientbcc
enabledService: managesieve
enabledService: managesievesecured
enabledService: sieve
enabledService: sievesecured
enabledService: lmtp
enabledService: sogo
enabledService: shadowaddress
enabledService: displayedInGlobalAddressBook
shadowLastChange: 18398
amavisLocal: TRUE

dn: mail=dwarynska@mydomain.com,ou=Users,domainName=mydomain.com,o=domains,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: mailUser
objectClass: shadowAccount
objectClass: amavisAccount
mail: dwarynska@mydomain.com
userPassword: {SSHA}XL1T9GV1SAqeRrsUx3K0C7eFSsTsm7AT
mailQuota: 5368709120
cn:: RGFyaWEgV2FyecWEc2th
sn: dwarynska
uid: dwarynska
storageBaseDirectory: /var/vmail
mailMessageStore: vmail1/mydomain.com/d/w/a/dwarynska-2020.05.16.20.20.07/
homeDirectory: /var/vmail/vmail1/mydomain.com/d/w/a/dwarynska-2020.05.16.20.20.07/
accountStatus: active
enabledService: internal
enabledService: doveadm
enabledService: lib-storage
enabledService: indexer-worker
enabledService: dsync
enabledService: quota-status
enabledService: mail
enabledService: smtp
enabledService: smtpsecured
enabledService: smtptls
enabledService: pop3
enabledService: pop3secured
enabledService: pop3tls
enabledService: imap
enabledService: imapsecured
enabledService: imaptls
enabledService: deliver
enabledService: lda
enabledService: forward
enabledService: senderbcc
enabledService: recipientbcc
enabledService: managesieve
enabledService: managesievesecured
enabledService: sieve
enabledService: sievesecured
enabledService: lmtp
enabledService: sogo
enabledService: shadowaddress
enabledService: displayedInGlobalAddressBook
shadowLastChange: 18398
amavisLocal: TRUE

dn: mail=adarecka@mydomain.com,ou=Users,domainName=mydomain.com,o=domains,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: mailUser
objectClass: shadowAccount
objectClass: amavisAccount
mail: adarecka@mydomain.com
userPassword: {SSHA}ObU/Ydy4GUnT1hM3Ebmk+GE4hYPBUlVp
mailQuota: 5368709120
cn: Anna Darecka
sn: adarecka
uid: adarecka
storageBaseDirectory: /var/vmail
mailMessageStore: vmail1/mydomain.com/a/d/a/adarecka-2020.05.16.20.20.07/
homeDirectory: /var/vmail/vmail1/mydomain.com/a/d/a/adarecka-2020.05.16.20.20.07/
accountStatus: active
enabledService: internal
enabledService: doveadm
enabledService: lib-storage
enabledService: indexer-worker
enabledService: dsync
enabledService: quota-status
enabledService: mail
enabledService: smtp
enabledService: smtpsecured
enabledService: smtptls
enabledService: pop3
enabledService: pop3secured
enabledService: pop3tls
enabledService: imap
enabledService: imapsecured
enabledService: imaptls
enabledService: deliver
enabledService: lda
enabledService: forward
enabledService: senderbcc
enabledService: recipientbcc
enabledService: managesieve
enabledService: managesievesecured
enabledService: sieve
enabledService: sievesecured
enabledService: lmtp
enabledService: sogo
enabledService: shadowaddress
enabledService: displayedInGlobalAddressBook
shadowLastChange: 18398
amavisLocal: TRUE

Taki plik możemy zaimportować do iRedMaila za pomocą polecenia (parametr -w pozwala na podanie hasła w parametrze, -W powoduje, że wpisywane hasło nie jest widziane na ekranie):

ldapadd -x -D cn=Manager,dc=domain,dc=com -f /home/supra/import.csv.ldif -w haslodokontamanagera

W efekcie powinniśmy dostać to:

adding new entry "mail=mmarecki@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"

adding new entry "mail=dwarynska@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"

adding new entry "mail=adarecka@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"

adding new entry "mail=tf2serv@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"

adding new entry "mail=bots@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"

Możemy spotkać się z takim błędem:

adding new entry "mail=supra@etf2l.site,ou=Users,domainName=domain.com,o=domains,dc=domain,dc=com"
ldap_add: Already exists (68)

To po prostu oznacza, że dany użytkownik istnieje i jeśli wcześniej mieliśmy jakieś linijki o powodzeniu dodania użytkownika, to musimy usunąć wszystko wyżej wraz z użytkownikiem, który istnieje tak, że pierwszą linią będzie pierwsze pole następnego użytkownika. Każdy wpis jest oddzielony pustą linią i powinniśmy zachować takie odstępy, lecz na początku tego nie trzeba mieć.

Wyszukiwanie użytkowników w LDAPie w konsoli i w GUI

W konsoli jest to proste, wystarczy polecenie ldapsearch:

ldapsearch -b dc=etf2l,dc=site -H ldap://127.0.0.1 -D cn=vmail,dc=etf2l,dc=site -w secretvmailadminpassword -s sub "(&(mailMessageStore=*)(cn=postmaster))"

Parametry to:

  • -b – domena, dla której wykonujemy zapytanie
  • -H – host, do którego wysyłamy zapytanie
  • -D – konto, które ma prawa do wykonania tego typu zapytań w postaci DN
  • -w – hasło do tego konta
  • -s – nasze zapytanie

Zapytanie wyżej wyświetla daje w wyniku konta, które mają dowolną wartość wpisaną w atrybucie mailMessageStore (ścieżka do skrzynki pocztowej użytkownika) oraz wartość postmaster wpisaną w atrybucie cn (common name, z reguły jest unikalne). Poniżej zapytanie, które pyta tylko o konta z cn o wartości postmaster:

ldapsearch -b dc=etf2l,dc=site -H ldap://127.0.0.1 -D cn=vmail,dc=etf2l,dc=site -w secretvmailadminpassword -s sub "(cn=postmaster)"

Jeśli chodzi o GUI to tutaj trzeba trochę pokombinować. Widziałem komentarze na forach odradzające korzystania z phpLDAPadmin, więc skorzystałem z LAM (LDAP Account Manager).

Na początku ściągamy pakiet na naszą dystrybucję, w moim przypadku nie było w repozytorium, więc ściągnąłem sobie plik .deb z sieci i go zainstalowałem:

wget https://netix.dl.sourceforge.net/project/lam/LAM/7.2/ldap-account-manager_7.2-1_all.deb
sudo dpkg -i ldap-account-manager_7.2-1_all.deb
sudo apt -f install -y

W ten sposób LAM będzie zainstalowany. Następnie musimy go wystawić poprzez stronę i to ułatwia LAM samo w sobie, bo w /etc/ldap-account-manager/nginx.conf znajdziemy szablon lokalizacji, który możemy dodać do strony:

location /lam {
        index index.html;
        alias /usr/share/ldap-account-manager;
        autoindex off;

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
                fastcgi_param SCRIPT_FILENAME $request_filename;
        }

        location ~ /lam/(tmp/internal|sess|config|lib|help|locale) {
                deny all;
                return 403;
        }

}

Trzeba tutaj poprawić linijkę, którą zaznaczyłem, bo pewnie nie używacie już takiej wersji PHP (OBY!). W domyślnej konfiguracji PHP aktualnej wersji pracuje pod adresem 127.0.0.1:9999, więc ta linijka powinna mieć fastcgi_pass 127.0.0.1:9999;. Ponadto dodałbym w tej lokalizacji takie dwie linijki, by ograniczyć dostęp do tej przeglądarki tylko z sieci, w której mamy możliwość administrowania wszystkim (w przykładzie będzie 192.168.10.0/24). Na lenia wrzuciłem konfigurację do /etc/nginx/sites-available/00-default-ssl.conf i dzięki temu dostanę się do strony wpisując w przeglądarce adres https://mail.domain.com/lam:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name mail.domain.com;

location /lam {
        allow 192.168.10.0/24;
        deny all;
        index index.html;
        alias /usr/share/ldap-account-manager;
        autoindex off;
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass 127.0.0.1:9999;
                fastcgi_param SCRIPT_FILENAME $request_filename;
        }

        location ~ /lam/(tmp/internal|sess|config|lib|help|locale) {
                deny all;
                return 403;
        }

}
    root /var/www/html;
    index index.php index.html;
    include /etc/nginx/templates/misc.tmpl;
    include /etc/nginx/templates/ssl.tmpl;
    include /etc/nginx/templates/iredadmin.tmpl;
    include /etc/nginx/templates/roundcube.tmpl;
    include /etc/nginx/templates/sogo.tmpl;
    include /etc/nginx/templates/netdata.tmpl;
    include /etc/nginx/templates/php-catchall.tmpl;
    include /etc/nginx/templates/stub_status.tmpl;
}

Po otwarciu strony musimy nieco zmienić konfigurację pod kątem logowania:

Następnie wybieramy Edytuj profile serwerowe:

W tym polu wpisujemy hasło lam i warto je zmienić:

W Ustawieniach głównych, sekcji Server settings ustawiamy odpowiedni DN domeny, do której się łączymy, przy okazji można zmienić język i strefę czasową:

Dodatkowo w Ustawieniach bezpieczeństwa definiujemy w polu Lista uprawnionych użytkowników definiujemy DN konta Manager:

Na końcu hasło do profilu warto sobie zmienić po to, by nikt nam tego profilu nie zmieniał:

Następnie możemy się zalogować wklejając hasło do konta Manager:

Ponadto warto sobie przejść do karty Typy kont i zmienić ustawienia Aktywuj rodzaje kont. Na tym etapie dałem sobie spokój z ukrywaniem mojej domeny, bo i tak do strony dostęp jest zablokowany:

W polach wpisałem:

  • Użytkownicy:
    • Sufiks LDAP: ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
    • Atrybuty listy: (to było za długie, by wpisać w liście)
uid;#cn;#accountStatus;#amavisLocal;#enabledService;#homeDirectory;#mail;#mailMessageStore;#mailQuota;#memberOfGroup;#objectClass;#shadowLastChange;#sn;#storageBaseDirectory;#userPassword
  • Grupy:
    • Sufiks LDAP: ou=Groups,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
    • Atrybuty listy: cn;#accountStatus;#enabledService;#mail;#mail;#objectClass

Po zmianach zapisujemy i logujemy się do konta Manager:

W ten sposób otrzymujemy ładną przeglądarkę kont:

Może nie tak ładną, wszystko przez pole enabledservice.

Tak czy siak mi lepiej się tego interfejsu używa poprzez Widok drzewa, który można znaleźć u góry, po prawej. W aktualnym interfejsie jest lepiej wyszukać coś, ale w tym drzewku łatwiej modyfikować i dodawać.

Dodajemy atrybuty poprzez pole Dodaj nowy atrybut po prawej stronie, następnie wybieramy z listy atrybut, który nas interesuje:

Potem jedynie wpisujemy, co chcemy i zapisujemy (przycisk jest na samym dole, Zaktualizuj obiekt). Tutaj przykład jeśli chcielibyśmy dodać użytkownikowi grupę po to, by po wysłaniu maila przez jakiegoś użytkownika na newsletter@etf2l.site otrzymywał wiadomości (inaczej mówiąc dodajemy użytkownika do wewnętrznej listy mailingowej):

Dodawanie aliasów

Na starym serwerze aliasy były przechowywane w pliku /etc/aliases, którego format był następujący:

suprovsky: supra
a.darecka: adarecka
ad: adarecka
admin: supra, adarecka

Po lewej znajduje się alias, po dwukropku znajduje się lista użytkowników, którzy mają otrzymywać wiadomości po odebraniu przez serwer wiadomości na alias, czyli np. wysyłka maila na admin@etf2l.site powoduje wysłanie maili do supra@etf2l.site oraz adarecka@etf2l.site.

W przypadku iRedMaila z OpenLDAP są dwie opcje, by to sobie dodać taki alias: przez LAM i przez polecenie ldapmodify z przygotowanym plikiem LDIF. W przypadku LAMa wystarczy, że dodamy nowy atrybut o nazwie shadowaddress i podamy po prostu pełny adres aliasu, czyli np. dla konta supra wartości atrybutu to suprovsky@etf2l.site oraz admin@etf2l.site.

Postać LDIF dla supra i adarecka wyglądałby następująco (trzeba pamiętać o dodaniu pustej linii pomiędzy wpisami):

dn: mail=supra@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
changetype: modify
add: shadowaddress
shadowaddress: suprovsky@etf2l.site
shadowaddress: admin@etf2l.site

dn: mail=adarecka@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
changetype: modify
add: shadowaddress
shadowaddress: a.darecka@etf2l.site
shadowaddress: ad@etf2l.site

Taki przygotowany LDIF zapisujemy do pliku, dajmy na to aliases.ldif i wrzucamy do LDAPa poleceniem:

ldapmodify -H ldap://127.0.0.1 -D cn=Manager,dc=etf2l,dc=site -f aliases.ldif -w 0PjBPdKWNgs3dWfux8BTK16wc6XCBF

W wyniku dostałem:

modifying entry "mail=supra@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site"

modifying entry "mail=adarecka@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site"

Czyli wszystko cacy.

Dodawanie grup (list mailingowych)

To akurat jest dosyć upierdliwe, bo jeśli chcemy dodać 1 grupę 500 użytkownikom to póki co nie znalazłem na to jakiejś magicznej sztuczki.

Ogólnie grupę tworzy się takim LDIFem (można go znaleźć tutaj):

dn: mail=all@etf2l.site,ou=Groups,domainName=mydomain.com,o=domains,dc=etf2l,dc=site
accountStatus: active
cn: demolist
enabledService: mail
enabledService: deliver
enabledService: displayedInGlobalAddressBook
mail: all@etf2l.site
objectClass: mailList
accesspolicy: domain

W tym LDIFie warto zwrócić uwagę na accesspolicy i poczytać w linku, który podałem wyżej. Wartość domain powoduje, że można na taką grupę wysyłać maile tylko z tej samej domeny. Dodajemy go tak:

ldapadd -x -D cn=Manager,dc=domain,dc=com -f /home/supra/newgroup.ldif -w haslodokontamanagera

Potem musimy do każdego obiektu, który ma należeć do wybranej grupy mailingowej (w tym przypadku all@etf2l.site) dodać atrybut z adresem mailowym takiej listy. Tutaj LDIF wygląda tak:

dn: mail=supra@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
changetype: modify
add: memberOfGroup
memberOfGroup: all@etf2l.site

I tutaj tak samo zmiany wprowadzamy poleceniem:

ldapmodify -H ldap://127.0.0.1 -D cn=Manager,dc=etf2l,dc=site -f addtogroup.ldif -w 0PjBPdKWNgs3dWfux8BTK16wc6XCBF

Modyfikowanie istniejących wpisów w LDAPie

To też sobie zapisałem, bo przydało mi się. ldapmodify można też używać w trybie interaktywnym, gdy się nie poda w argumencie -f pliku LDIF. Wtedy dane z w takim formacie podaje się wpisując je ręcznie i oddzielając enterami. Po wpisaniu całego wpisu należy zrobić linijkę przerwy i wykonać skrót Ctrl+D. To spowoduje wyjście z trybu interaktywnego i wykonanie zapytania do LDAPa. Przykład:

ldapmodify -H ldap://127.0.0.1 -D cn=Manager,dc=etf2l,dc=site -w 0PjBPdKWNgs3dWfux8BTK16wc6XCBF

Następnie dane, które wpisałem:

dn: mail=supra@etf2l.site,ou=Users,domainName=etf2l.site,o=domains,dc=etf2l,dc=site
changetype: modify
replace: memberOfGroup
memberOfGroup: newsletter@etf2l.site

W ten sposób z poprzednio ustawionego pola memberOfGroup na all@etf2l.site użytkownik supra będzie miał ustawioną grupę newsletter@etf2l.site.

Usunięcie domeny z pola logowania dla iRedMail (konkretnie SOGo)

Jest to tutaj opisane, ale nie dla SOGo. Do tego się odniosę. Trzeba edytować 1 plik, mianowicie /etc/sogo/sogo.conf, lecz przed tym trzeba sobie umożliwić jego modyfikację:

sudo chmod o+w /etc/sogo/sogo.conf

W pliku modyfikuję takie pola (podaję wartości, które ustawiam, nie wszystko dotyczy samego usunięcia z domeny, bo część to po prostu dobre praktyki):

SOGoLanguage = Polish;
SOGoForceExternalLoginWithEmail = NO;
SOGoTimeZone = "Europe/Warsaw";
SOGoUserSources = (
///zmieniamy tylko te pola///
bindDN = "cn=vmail,dc=etf2l,dc=site"; //usunąłem 'o=domains,' stąd
bindFields = (uid); //domyślna wartość to mail
)

Po zmianach restartujemy usługę poleceniem systemctl restart sogo i sprawa załatwiona.

Autokonfiguracja klientów pocztowych

Zbawienie dla administratorów. Wpisujesz nazwę użytkownika, maila i hasło. To wszystko. Brzmi zbyt pięknie, by było prawdziwe? Niekoniecznie musi! Są 2 gotowe formatki, które można wykorzystać i one są dla Microsoft Outlook oraz Mozilla Thunderbird. Sytuacja jest prosta: należy ustawić odpowiednie wpisy w DNSie i wystawić pliki na serwerze WWW.

Tutaj można zauważyć 2 wpisy CNAME autoconfig i autodiscover kierujące połączenia na domenę mail.etf2l.site, która jest innym CNAME, który kieruje na etf2l.site, a ten już kieruje na odpowiedni adres IP (to jest wpis A). To będzie nam potrzebne. Te dwa CNAME mają po prostu wskazywać serwer, na którym są formatki, które ma pobierać klient pocztowy. W dodatku nie musi być to bezpośrednio nasz serwer mailowy, ale zrobiłem tak, bo tak po prostu mi było łatwiej. Ponadto powinniśmy mieć wpis SRV _autodiscover._tcp, który kieruje na adres serwera, na którym jest taka formatka. W wartości powinniśmy wpisać 0 1 443 mail.etf2l.site, przy czym zmieniamy adres naszego serwera formatki na właściwy.

Wyjaśnimy sobie po co są te domeny. Domena autodiscover.etf2l.site (konkretnie adres https://autodiscover.etf2l.site/autodiscover/autodiscover.xml jest wykorzystywna przez Outlooka do wykrycia konfiguracji poczty. W sumie to nie musimy mieć nawet do tego subdomeny, bo na dobrą sprawę moglibyśmy wystawiać to na domenie etf2l.site bezpośrednio – to jest kwestia czysto seperacji konfiguracji. Strona autoconfig.etf2l.site jest zaś dla Thunderbirda – on łączy się na adres https://autoconfig.etf2l.site/mail/config-v1.1.xml i z niego zaciąga sobie konfigurację. Tutaj subdomena akurat jest potrzebna.

Outlook widząc domenę etf2l.site sprawdza wpis SRV, o którym wspomniałem by sprawdzić pod jakim adresem jest plik konfiguracyjny, następnie wysyła na adres wspomniany wyżej w POST taką zawartość:

 <?xml version="1.0" encoding="utf-8"?> 
 <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006"> 
 <Request>
 <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema> 
 <EMailAddress>supra@etf2l.site</EMailAddress> 
 </Request> 
</Autodiscover>

Jak można zauważyć, w polu EMailAddress jest adres użytkownika, który próbuje sobie skongurować Outlooka. Dla Outlooka nie wystawiamy autodiscover.xml w postaci gołego XMLa – możemy do tego wykorzystać skrypt w PHP, który wpisuje nam adres mailowy użytkownika w XML, a następnie nam go zwraca (musimy ten XML edytować podając prawidłowe dane do naszego serwera pocztowego):

<?php
//get raw POST data so we can extract the email address
$data = file_get_contents("php://input");
preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $data, $matches);

//set Content-Type
header("Content-Type: application/xml");
?>
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
    <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Account>
            <AccountType>email</AccountType>
            <Action>settings</Action>
            <Protocol>
                <Type>IMAP</Type>
                <Server>mail.etf2l.site</Server>
                <Port>993</Port>
                <DomainRequired>off</DomainRequired>
                <LoginName><?php echo $matches[1]; ?></LoginName>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
            </Protocol>
            <Protocol>
                <Type>POP3</Type>
                <Server>mail.etf2l.site</Server>
                <Port>995</Port>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
                <?php echo $LoginName; ?>
            </Protocol>
            <Protocol>
                <Type>SMTP</Type>
                <Server>mail.etf2l.site</Server>
                <Port>465</Port>
                <DomainRequired>off</DomainRequired>
                <LoginName><?php echo $matches[1]; ?></LoginName>
                <SPA>off</SPA>
                <AuthRequired>on</AuthRequired>
                <UsePOPAuth>off</UsePOPAuth>
                <SMTPLast>off</SMTPLast>
            </Protocol>
        </Account>
    </Response>
</Autodiscover>

Warto wziąć pod uwagę, że jako SMTP określiłem połączenie SSL/TLS na porcie 465 – w większości użytkownicy będą woleli korzystać ze STARTTLS na porcie 587. Korzystałem z 465 w ramach testu, bo UPC nie blokuje tego portu 😂

W praktyce ze STARTTLSem na 587 powinniśmy podmienić w ten sposób sekcję Protocol:

            <Protocol>
                <Type>SMTP</Type>
                <Server>mail.etf2l.site</Server>
                <Port>587</Port>
                <DomainRequired>off</DomainRequired>
                <LoginName><?php echo $matches[1]; ?></LoginName>
                <SPA>off</SPA>
                <Encryption>TLS</Encryption>
                <AuthRequired>on</AuthRequired>
                <UsePOPAuth>off</UsePOPAuth>
                <SMTPLast>off</SMTPLast>
            </Protocol>

W naszym przykładzie będziemy przechowywać te formatki w katalogu /var/www/autodiscover (może być to dowolna inna lokalizacja, po prostu przyjęło się, że w /var/www z reguły są pliki wystawiane przez serwer HTTP). Ten plik będzie nazwany jako autodiscover.php. Do tego config, który jest potrzebny dla nginxa, by wystawiał dostęp dla tej domeny i do tego pliku (umieściłem go w /etc/nginx/sites-available/autodiscover.etf2l.site:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name autodiscover.etf2l.site;
    root /var/www/autodiscover;
    index index.php;
        include /etc/nginx/templates/ssl.tmpl;
        error_log /var/log/nginx/autodiscover-error.log;
        access_log /var/log/nginx/autodiscover-access.log combined;
        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }
    location ~ /(?:a|A)utodiscover/(?:a|A)utodiscover.xml {
        root /var/www/;
        try_files /autodiscover/autodiscover.php =404;
        fastcgi_pass 127.0.0.1:9999; #w tym miejscu jest prawidłowa wartość dla serwera z iredmailem
        fastcgi_index  index.php;
        include        fastcgi.conf;
        fastcgi_param SERVER_ADDR "";
        fastcgi_param REMOTE_ADDR $http_x_real_ip;
    }
}

Następnie należy dodać sobie symlink takiego configa do /etc/nginx/sites-enabled, by był wykorzystywany przez nginxa i warto też wykonać test konfiguracji, by sprawdzić, czy nie wkradł nam się do configa jakiś błąd przed restartem usługi. Jeśli taki będzie i zrestartujemy usługę, ta się nie uruchomi po zatrzymianiu i to może dla nas być problem. Test wykonuje się poleceniem nginx -t. Taki jest poprawny wynik testu:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Koniec końców linkuję konfig, wykonuję test i restartuję usługę tak:

cd /etc/nginx/sites-enabled
ln -s ../sites-available/autodiscover.etf2l.site
nginx -t
systemctl restart nginx

Następnie możemy sobie przetestować, czy taka formatka nam działa wykonując ręczny test za pomocą cURLa. Musimy zapisać sobie wspomniany na początku request do pliku. Nazwijmy go req.xml, następnie wykonujemy następujące polecenie:

curl -X POST file:/home/supra/req.xml https://autodiscover.etf2l.site/autodiscover/autodiscover.xml

W wyniku otrzymałem:

<?xml version="1.0" encoding="utf-8"?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
  <Request>
    <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
    <EMailAddress>supra@etf2l.site</EMailAddress>
  </Request>
</Autodiscover>
<?xml version="1.0" encoding="utf-8" ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
    <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Account>
            <AccountType>email</AccountType>
            <Action>settings</Action>
            <Protocol>
                <Type>IMAP</Type>
                <Server>mail.etf2l.site</Server>
                <Port>993</Port>
                <DomainRequired>off</DomainRequired>
                <LoginName></LoginName>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
            </Protocol>
            <Protocol>
                <Type>POP3</Type>
                <Server>mail.etf2l.site</Server>
                <Port>995</Port>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
                            </Protocol>
            <Protocol>
                <Type>SMTP</Type>
                <Server>mail.etf2l.site</Server>
                <Port>465</Port>
                <DomainRequired>off</DomainRequired>
                <LoginName></LoginName>
                <SPA>off</SPA>
                <AuthRequired>on</AuthRequired>
                <UsePOPAuth>off</UsePOPAuth>
                <SMTPLast>off</SMTPLast>
            </Protocol>
        </Account>
    </Response>
</Autodiscover>

To oznacza, że wszystko się zgadza. Z poziomu Outlooka wygląda to tak:

W przypadku Thunderbirda jest podobnie, lecz nie trzeba robić sztuczek z PHPem – wystarczy w odpowiedni sposób przygotować plik XML (umieszczając go w /var/www/autodiscover) oraz umieścić do niego pasujący plik konfiguracyjny do nginxa (oczywiście na Apache’u też to można zrobić, ale dla mnie Apache śmierdzi i nie będę go używał):

<?xml version="1.0" encoding="UTF-8"?>

<clientConfig version="1.1">
    <emailProvider id="etf2l.site">
        <domain>mail.etf2l.site</domain>
        <displayName>Mail</displayName>
        <displayShortName>Mail</displayShortName>
        <incomingServer type="imap">
            <hostname>mail.etf2l.site</hostname>
            <port>993</port>
            <socketType>SSL</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </incomingServer>
        <incomingServer type="imap">
            <hostname>mail.etf2l.site</hostname>
            <port>143</port>
            <socketType>STARTTLS</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </incomingServer>
        <outgoingServer type="smtp">
            <hostname>mail.etf2l.site</hostname>
            <port>465</port>
            <socketType>SSL</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </outgoingServer>
        <outgoingServer type="smtp">
            <hostname>mail.etf2l.site</hostname>
            <port>587</port>
            <socketType>STARTTLS</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </outgoingServer>
    </emailProvider>
</clientConfig>

W tym XMLu kolejność protokołów ma znaczenie, wiec jeśli chcemy w pierwszej kolejności używać portu 587 zamiast 465 to musimy zamienić sekcje outgoingServer miejscami. Następnie config do nginxa wygląda tak:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name autoconfig.etf2l.site;
        location ^~ /mail {
        alias /var/www/autodiscover;
        try_files $uri =404;
}
    root /var/www/autodiscover;
    index index.php;
        include /etc/nginx/templates/ssl.tmpl;
        error_log /var/log/nginx/autodiscover-error.log;
        access_log /var/log/nginx/autodiscover-access.log combined;

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }
}

Po zrobieniu symlinka do tego configa w /etc/nginx/sites-enabled, zrobieniu testu i zrestartowaniu nginxa możemy zobaczyć jak nasz Thunderbird się sam konfiguruje:

Jest też opcja, by móc automatycznie konfigurować sprzęt Apple’a, ale jestem zbyt leniwy, by to przetestować. Jest to opisane tutaj.

Zabezpieczenie się przed niepowołanym dostępem do administracji

Jest kilka rzeczy, które powinno się zrobić z mojego punktu widzenia, by zminimalizować ryzyko, że ktoś niepowołany wejdzie na jakąś stronę. Po pierwsze, należy obciąć dostęp do LDAP Account Managera/phpLDAPadmin (jeśli zainstalowany) w nginxie, następnie to należy powtórzyć dla lokalizacji w plikach:

  • /etc/nginx/templates/adminer.tmpl,
  • /etc/nginx/templates/iredadmin.tmpl,
  • /etc/nginx/templates/iredadmin.tmpl-subdomain.tmpl,
  • /etc/nginx/templates/netdata.tmpl,
  • /etc/nginx/templates/netdata-subdomain.tmpl.

Przykład w /etc/nginx/templates/iredadmin.tmpl:

# Settings for iRedAdmin.

# static files under /iredadmin/static
location ~ ^/iredadmin/static/(.*) {
    alias /opt/www/iredadmin/static/$1;
}

# Python scripts
location ~ ^/iredadmin(.*) {
    allow 192.168.10.0/24;
    deny all;
    rewrite ^/iredadmin(/.*)$ $1 break;

    include /etc/nginx/templates/hsts.tmpl;

    include uwsgi_params;
    uwsgi_pass 127.0.0.1:7791;
    uwsgi_param UWSGI_CHDIR /opt/www/iredadmin;
    uwsgi_param UWSGI_SCRIPT iredadmin;
    uwsgi_param SCRIPT_NAME /iredadmin;

    # Access control
    #allow 127.0.0.1;
    #allow 192.168.1.10;
    #allow 192.168.1.0/24;
    #deny all;
}

# iRedAdmin: redirect /iredadmin to /iredadmin/
location = /iredadmin {
    rewrite ^ /iredadmin/;
}

# Handle newsletter-style subscription/unsubscription supported in iRedAdmin-Pro.
location ~ ^/newsletter/ {
    rewrite /newsletter/(.*) /iredadmin/newsletter/$1 last;

Po zmianach wiadomo, restarcik nginxa się przyda: systemctl restart nginx.

Poza tym powinno się nasłuchiwać połączenia serwera SSH tylko i wyłącznie z podsieci administracyjnej, powinno się wyłączyć logowanie na roota po SSH oraz wyłączyć logowanie za pomocą haseł i przerzucić się na klucze publiczne zmieniając plik /etc/ssh/sshd_config (zamieszczam tylko istotny fragment):

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
PermitRootLogin no
PubkeyAuthentication yes

# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile     .ssh/authorized_keys .ssh/authorized_keys2

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
PermitEmptyPasswords no

Dostęp z innych podsieci możemy załatwić za pomocą iptables:

iptables -A INPUT -p tcp --dport 22 --source 192.168.10.0/24 -j ACCEPT

Warto też się upewnić, że domyślna polityka INPUT dla iptables to DROP (to oznacza, że dla każdego ruchu niezdefiniowanego w regułach iptables w sekcji INPUT jest wykonywany DROP, czyli brak odpowiedzi):

sudo iptables -L -v
[sudo] password for supra:
Chain INPUT (policy DROP 1803K packets, 167M bytes)

Do iptables warto mieć opcję zapisywania konfiguracji i można znaleźć o tym fajny poradnik tutaj.

Integracja Active Directory z Linuksem oraz przydzielanie uprawnień administracyjnych na prawach grup

Przeczytasz to w: 8 minut

Akurat to użycie integracji nie daje aż takich korzyści w stosunku do integracji AD na przykład z FortiGate’m, ale nadal można to wykorzystać w ciekawy sposób niespecjalnie pocąc się przy konfiguracji. Założenie jest dosyć proste – umożliwić logowanie się na konta z domeny Active Directory (najnornalniejszej na świecie, żadne udziwnienia w postaci AD na QNAPie czy tym podobne) oraz umożliwić konkretnej grupie w AD korzystanie z uprawnień administracyjnych (aka korzystanie z polecenia sudo).

Moje środowisko składa się z dwóch kontrolerów domeny, ad1.serba.local (192.168.30.2) i ad2.serba.local (192.168.30.3). Do tego są inne hosty w sieci, które są totalnie nieistotne. Jak FQDNy wskazują, moja nazwa domeny to serba.local. Grupa, której damy uprawnienia administracyjne w Linuksach to wbudowana grupa AD Administratorzy domeny. Adres sieci to 192.168.30.0/24 i pierwszy użyteczny adres to adres routera. Przykład integracji opieram na Windowsach Server 2019 v. 1809, Xubuntu 19.10 i Red Hat Enterprise Linux 8.0. Dobrałem takie 2 dystrybucje Linuksa ze względu na to, że one i ich pochodne (przy czym Ubuntu jest pochodną Debiana te podobieństwo działa w drugą stronę) są bardzo podobne w konfiguracji, więc w jednym poradniku będzie można zobaczyć jak zrobić taką integrację na większości dystrybucji. W praktyce powinniśmy być w stanie zintegrować dowolną dystrybucję Linuksa posiadając zainstalowane w systemie odpowiednie pakiety.

Integracja AD na (X)ubuntu

Na początku zaczynamy od instalacji potrzebnych pakietów:

# apt install adcli realmd krb5-user samba-common-bin samba-libs samba-dsdb-modules sssd sssd-tools libnss-sss libpam-sss packagekit policykit-1

Następnie edytujemy plik /etc/samba/smb.conf w sekcji [global] (ta sekcja zaczyna się pod tym nagłówkiem, a kończy się z miejscem kolejnego):

   workgroup = SERBA #tutaj nazwa NETBIOS domeny
   client signing = yes
   client use spnego = yes
   kerberos method = secrets and keytab
   realm = SERBA.LOCAL #koniecznie dużymi literami
   security = ads
   idmap config *: range = 10000-20000 #bez dodania tego parametru nie przechodził test cfg

Po wykonaniu zmian warto przetestować, czy wszystko w tym pliku konfiguracyjnym jest OK, w innym wypadku sługi smbd i nmbd nie uruchomią się po restarcie. Robimy to poleceniem sudo testparm:

Następnie edytujemy /etc/sssd/sssd.conf (ten plik domyślnie nie istnieje, więc nie zdziwcie się, jeśli pliku nie będzie):

[nss]
filter_groups = root
filter_users = root
reconnection_retries = 3

[pam]
reconnection_retries = 3

[sssd]
domains = serba.local #tutaj nazwa domeny małymi literami
config_file_version = 2
services = nss, pam
default_domain_suffix = SERBA.LOCAL #tutaj domena dużymi literami
full_name_format = %1$s #dzięki tej linijce nie musimy wpisywać `użytkownik@domena` tylko wystarczy `użytkownik`

[domain/serba.local] #małymi literami domena
ad_domain = serba.local #ponownie domena małymi literami
krb5_realm = SERBA.LOCAL #tym razem domena dużymi literami
realmd_tags = manages-system joined-with-samba
cache_credentials = True
id_provider = ad
krb5_store_password_if_offline = True
default_shell = /bin/bash #definiujemy shell dla logujących się użytkowników AD, może być inny
ldap_id_mapping = True
use_fully_qualified_names = True
fallback_homedir = /home/%d/%u #składnia: /home/<nazwa-domeny>/<nazwa-uzytkownika>
access_provider = ad

auth_provider = ad
chpass_provider = ad
access_provider = ad
ldap_schema = ad
dyndns_update = true
dyndns_refresh_interval = 43200
dyndns_update_ptr = true
dyndns_ttl = 3600

Po stworzeniu konfiguracji musimy zabezpieczyć plik w ten sposób, by inni poza rootem nie mieli do niego dostępu:

# chown 600 /etc/sssd/sssd.conf
# chown root:root /etc/sssd/sssd.conf

Następnie definiujemy plik /etc/realmd.conf:

[active-directory]
os-name = Linux Ubuntu
os-version = 19.04

[service]
automatic-install = yes

 [users]
default-home = /home/%d/%u
default-shell = /bin/bash

[serba.local]
user-principal = yes
fully-qualified-names = no

[providers]
samba = no #bez tej linijki są problemy z logowaniem ze wskazaniem uprawnień grup do logowania poprzez realm

Mając to zrobione musimy zrestartować usługi, które konfigurowaliśmy:

# systemctl restart smbd nmbd sssd realmd

Następnie możemy sprawdzić, czy mamy połączenie z domeną pobierając „bilecik” z KDC poprzez polecenie kinit określając nazwę użytkownika@domenę, z której się logujemy:

# kinit rserba@SERBA.LOCAL
Password for rserba@SERBA.LOCAL: 
# /etc/sssd > klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: rserba@SERBA.LOCAL

Valid starting       Expires              Service principal
02.04.2020 21:04:52  03.04.2020 07:04:52  krbtgt/SERBA.LOCAL@SERBA.LOCAL
renew until 09.04.2020 21:04:49

Po tym możemy dołączyć naszym Linuksowym hostem do domeny AD. Najpierw sprawdźmy, czy jesteśmy w stanie wykryć domenę w naszej sieci poleceniem realm discover -v NAZWA.DOMENY:

# realm discover -v SERBA.LOCAL
 * Resolving: _ldap._tcp.serba.local
 * Performing LDAP DSE lookup on: 192.168.30.3
 * Performing LDAP DSE lookup on: 192.168.30.2
 * Successfully discovered: serba.local
serba.local
  type: kerberos
  realm-name: SERBA.LOCAL
  domain-name: serba.local
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: sssd-tools
  required-package: sssd
  required-package: libnss-sss
  required-package: libpam-sss
  required-package: adcli
  required-package: samba-common-bin
  login-formats: %U@serba.local
  login-policy: allow-realm-logins

I teraz już na serio dołączamy do domeny poleceniem realm join NAZWA.DOMENY -U konto_admina -v:

# realm join SERBA.LOCAL -U rserba -v
 * Resolving: _ldap._tcp.serba.local
 * Performing LDAP DSE lookup on: 192.168.30.3
 * Performing LDAP DSE lookup on: 192.168.30.2
 * Successfully discovered: serba.local
realm: Już dołączono do tej domeny

Powtarzamy poleceniem net ads join -k:

# net ads join -k
Using short domain name -- SERBA
Joined 'SUPRA-VM' to dns domain 'serba.local'

Następnie musimy ograniczyć logowanie do tego hosta poprzez wskazanie grupy, która może się logować oraz reszty, która tego robić nie może. Pierwszym poleceniem blokujemy dostęp wszystkim użytkownikom, a następnie dodajemy grupę, która może się logować do tego systemu. Wszyscy członkowie tej grupy mogą się zalogować.

# realm deny -a                                            
# realm permit --groups 'serba.local\Administatorzy domeny'

Przed zalogowaniem się musimy też umożliwić automatyczne tworzenie katalogów dla użytkowników (w innym wypadku na dobrą sprawę użytkownicy AD nie będą w stanie normalnie funkcjonować w systemie na własnych prawach):

# pam-auth-update

Po otwarciu okna zaznaczamy Create home directory on login i dajemy OK:

Warto też sprawdzić plik /etc/nsswitch.conf, w sekcjach passwd, group i shadow, netgroup, services i sudoers powinno być dopisane na końcu sss:

Po tym powinniśmy dodać do /etc/pam.d/common-account linijkę na samym dole pliku:

session    required    pam_mkhomedir.so    skel=/etc/skel/    umask=0022

I teraz instalujemy winbind po to, by móc wykorzystać konta AD w ekranie logowania:

# apt install winbind

Usługa winbind.service powinna się uruchomić od razu po instalacji. Sprawdźmy, czy możemy pobrać użytkowników i grupy z AD poleceniami wbinfo -u i wbinfo -g:

# wbinfo -u
SERBA\administrator
SERBA\gość
SERBA\krbtgt
SERBA\fsso
SERBA\rserba
SERBA\smatuszczyk
SERBA\serviceacc
SERBA\mblaszczyk
SERBA\dkania
# wbinfo -g
SERBA\komputery domeny
SERBA\kontrolery domeny
SERBA\administratorzy domeny
SERBA\użytkownicy domeny
SERBA\goście domeny
SERBA\twórcy-właściciele zasad grupy
SERBA\kontrolery domeny tylko do odczytu
SERBA\klonowalne kontrolery domen
SERBA\protected users
SERBA\administratorzy kluczy
SERBA\dnsupdateproxy
SERBA\wydawcy certyfikatów
SERBA\serwery ras i ias
SERBA\grupa z replikacją haseł na kontrolerach rodc
SERBA\grupa bez replikacji haseł na kontrolerach rodc
SERBA\dnsadmins
SERBA\administratorzy schematu
SERBA\administratorzy przedsiębiorstwa
SERBA\kontrolery domeny tylko do odczytu na poziomie organizacji
SERBA\administratorzy kluczy przedsiębiorstwa

Jak widać, działa. Sprawdźmy, czy jesteśmy sprawdzić informacje o użytkowniku rserba:

# sudo getent passwd rserba 
rserba@serba.local:*:599001107:599000513:Radosław Serba:/home/serba.local/rserba:/bin/bash
# id rserba
uid=599001107(rserba@serba.local) gid=599000513(użytkownicy domeny@serba.local) grupy=599000513(użytkownicy domeny@serba.local),599000512(administratorzy domeny@serba.local),599000572(grupa bez replikacji haseł na kontrolerach rodc@serba.local)

Na końcu dodamy grupę Administratorzy domeny do /etc/sudoers i umożliwimy na logowanie poprzez interfejs graficzny (wykorzystując menedżer wyświetlania LightDM). Edytujemy /etc/sudoers (plik określający kto w tym systemie może korzystać z polecenia sudo) poleceniem visudo (jak root) i dodajemy linijkę:

#%SERBA\\administratorzy\ domeny        ALL=(ALL:ALL) ALL #nieadekwatny do przykładu
#%administratorzy\ domeny@serba.local   ALL=(ALL:ALL) ALL #nieadekwatny do przykładu
%administratorzy\ domeny        ALL=(ALL:ALL) ALL

Potem edytujemy plik /usr/share/lightdm/lightdm.conf.d/60-xubuntu.conf (na dobrą sprawę możemy sobie nawet sami utworzyć nowy plik w katalogu /usr/share/lightdm/lightdm.conf.d i upewnić się, że będzie miał prawidłową składnię) i dodajemy:

greeter-show-manual-login=true
greeter-hide-users=true

Dzięki temu trzeba będzie wpisać w pole logowania nazwę użytkownika i hasła i w ten sposób będzie można się logować na pulpit tak samo, jak lokalni użytkownicy. Zmiany są widoczne po restarcie usługi lightdm.service, więc możemy po prostu uruchomić system ponownie i wszystko powinno już wejść w życie.

Przy okazji próbując zmienić konto poprzez polecenie su - nazwa_usera_ad możemy sprawdzić czy ograniczenia na logowanie działają:

 supra@supra-vm > ~ > su - rserba
Hasło: 
rserba@supra-vm:~$ exit
wylogowanie
 supra@supra-vm > ~ > su - smatuszczyk
Hasło: 
su: Uwierzytelnienie się nie powiodło

W ten sposób wszystko działa poprawnie, przetestujmy sudo:

rserba@supra-vm:~$ sudo apt update
[sudo] hasło użytkownika rserba: 
Niestety, proszę spróbować ponownie.
[sudo] hasło użytkownika rserba: 
Stary:1 http://pl.archive.ubuntu.com/ubuntu eoan InRelease
Pobieranie:2 http://pl.archive.ubuntu.com/ubuntu eoan-updates InRelease [97,5 kB]
Pobieranie:3 http://pl.archive.ubuntu.com/ubuntu eoan-backports InRelease [88,8 kB]
Pobieranie:4 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main i386 Packages [192 kB]
Pobieranie:5 http://security.ubuntu.com/ubuntu eoan-security InRelease [97,5 kB]
Pobieranie:6 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main amd64 Packages [258 kB]
Pobieranie:7 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main Translation-en [95,3 kB]
Pobieranie:8 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main amd64 DEP-11 Metadata [79,0 kB]
Pobieranie:9 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main DEP-11 48x48 Icons [14,6 kB]
Pobieranie:10 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main DEP-11 64x64 Icons [24,7 kB]
Pobieranie:11 http://pl.archive.ubuntu.com/ubuntu eoan-updates/main amd64 c-n-f Metadata [8 184 B]
Pobieranie:12 http://pl.archive.ubuntu.com/ubuntu eoan-updates/restricted amd64 Packages [14,4 kB]
Pobieranie:13 http://pl.archive.ubuntu.com/ubuntu eoan-updates/restricted Translation-en [1 976 B]
Pobieranie:14 http://pl.archive.ubuntu.com/ubuntu eoan-updates/universe Translation-en [74,4 kB]
Pobieranie:15 http://pl.archive.ubuntu.com/ubuntu eoan-updates/universe amd64 DEP-11 Metadata [30,4 kB]
Pobieranie:16 http://pl.archive.ubuntu.com/ubuntu eoan-updates/universe DEP-11 48x48 Icons [20,5 kB]
Pobieranie:17 http://pl.archive.ubuntu.com/ubuntu eoan-updates/universe DEP-11 64x64 Icons [45,7 kB]
Pobieranie:18 http://pl.archive.ubuntu.com/ubuntu eoan-backports/universe amd64 DEP-11 Metadata [7 760 B]
Pobieranie:19 http://security.ubuntu.com/ubuntu eoan-security/main amd64 DEP-11 Metadata [7 388 B]
Pobieranie:20 http://security.ubuntu.com/ubuntu eoan-security/universe amd64 DEP-11 Metadata [4 852 B]
Pobrano 1 163 kB w 1s (1 120 kB/s)                
Czytanie list pakietów... Gotowe
Budowanie drzewa zależności       
Odczyt informacji o stanie... Gotowe
5 packages can be upgraded. Run 'apt list --upgradable' to see them.

Integracja AD na Red Hat Enterprise Linux

Moje instrukcje są inspirowane instrukcją, którą można znaleźć w Bazie Wiedzy Red Hata z drobnymi zmianami. Na początku instalujemy potrzebne pakiety:

# yum install adcli sssd authconfig realmd sssd oddjob oddjob-mkhomedir samba-common samba-common-tools krb5-workstation -y

Tutaj trochę od końca zaczniemy – najpierw wykrywamy domenę poleceniem adcli info nazwa.domeny:

[root@rhel8 ~]# adcli info serba.local
[domain]
domain-name = serba.local
domain-short = SERBA
domain-forest = serba.local
domain-controller = dc2.serba.local
domain-controller-site = Default-First-Site-Name
domain-controller-flags = gc ldap ds kdc timeserv closest writable full-secret ads-web
domain-controller-usable = yes
domain-controllers = dc2.serba.local dc1.serba.local
[computer]
computer-site = Default-First-Site-Name

Następnie dołączamy do domeny za pomocą adcli join nazwa.domeny -U konto_admina:

[root@rhel8 ~]# adcli join serba.local -U rserba
Password for rserba@SERBA.LOCAL: 

Sprawdźmy, czy mamy pobrany „bilecik” z KDC:

[root@rhel8 ~]# klist -kte
Keytab name: FILE:/etc/krb5.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   2 06.04.2020 16:36:24 RHEL8$@SERBA.LOCAL (aes128-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 RHEL8$@SERBA.LOCAL (aes256-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 host/RHEL8@SERBA.LOCAL (aes128-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 host/RHEL8@SERBA.LOCAL (aes256-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 host/rhel8.serba.local@SERBA.LOCAL (aes128-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 host/rhel8.serba.local@SERBA.LOCAL (aes256-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 RestrictedKrbHost/RHEL8@SERBA.LOCAL (aes128-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 RestrictedKrbHost/RHEL8@SERBA.LOCAL (aes256-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 RestrictedKrbHost/rhel8.serba.local@SERBA.LOCAL (aes128-cts-hmac-sha1-96) 
   2 06.04.2020 16:36:24 RestrictedKrbHost/rhel8.serba.local@SERBA.LOCAL (aes256-cts-hmac-sha1-96)

Okej, na tym etapie musimy też edytować plik /etc/krb5.conf:

# To opt out of the system crypto-policies configuration of krb5, remove the
# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
includedir /etc/krb5.conf.d/

[logging]
    default = FILE:/var/log/krb5libs.log
    kdc = FILE:/var/log/krb5kdc.log
    admin_server = FILE:/var/log/kadmind.log

[libdefaults]
    dns_lookup_realm = true
    dns_lookup_kdc = true
    ticket_lifetime = 24h
    renew_lifetime = 7d
    forwardable = true
    udp_preference_limit = 1
    rdns = false
    pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
    spake_preauth_groups = edwards25519
    default_realm = SERBA.LOCAL #tak, domena musi być z dużej litery
    default_ccache_name = KEYRING:persistent:%{uid}

[realms]
SERBA.LOCAL = { #tutaj podobnie
    kdc = serba.local #nie wpisujemy poszczególnych kontrolerów domeny, jeśli discovery działa to nie ma sensu podawać tutaj FQDNa kontrolera
    admin_server = serba.local #podobnie, w obu przypadkach podajemy z małych liter nazwę domeny
}

[domain_realm]
.serba.local = SERBA.LOCAL #w obu przypadkach z dużej litery domena
serba.local = SERBA.LOCAL

Okej, mając to ustawione zastosujmy konfigurację poleceniem authconfig --enablesssd --enablesssdauth --enablelocauthorize --enablemkhomedir --update:

[root@rhel8 ~]# authconfig --enablesssd --enablesssdauth --enablelocauthorize --enablemkhomedir --update
Running authconfig compatibility tool.
The purpose of this tool is to enable authentication against chosen services with authselect and minimum configuration. It does not provide all capabilities of authconfig.

IMPORTANT: authconfig is replaced by authselect, please update your scripts.
See man authselect-migration(7) to help you with migration to authselect
Warning: These options are not supported anymore and have no effect:
  --enablelocauthorize

Executing: /usr/bin/authselect check
Executing: /usr/bin/authselect select sssd with-mkhomedir --force
Executing: /usr/bin/systemctl enable sssd.service
Executing: /usr/bin/systemctl stop sssd.service
Executing: /usr/bin/systemctl start sssd.service
Executing: /usr/bin/systemctl enable oddjobd.service

Executing: /usr/bin/systemctl stop oddjobd.service
Executing: /usr/bin/systemctl start oddjobd.service

Dobra, teraz upewnijmy się, że /etc/sssd/sssd.conf wygląda mniej więcej tak (jeśli nie, warto to nieco skorygować):

[nss]
filter_groups = root
filter_users = root
reconnection_retries = 3

[pam]
reconnection_retries = 3

[sssd]
domains = serba.local
config_file_version = 2
services = nss, pam
default_domain_suffix = SERBA.LOCAL
full_name_format = %1$s

[domain/serba.local]
ad_domain = serba.local
krb5_realm = SERBA.LOCAL
realmd_tags = manages-system joined-with-samba
cache_credentials = True
id_provider = ad
krb5_store_password_if_offline = True
default_shell = /bin/bash
ldap_id_mapping = True
use_fully_qualified_names = True
fallback_homedir = /home/%d/%u
access_provider = ad

auth_provider = ad
chpass_provider = ad
access_provider = ad
ldap_schema = ad
dyndns_update = true
dyndns_refresh_interval = 43200
dyndns_update_ptr = true
dyndns_ttl = 3600

Jeśli zmienimy cokolwiek, restartujemy usługę (od razu sobie warto ustawić ją tak, by uruchamiała się wraz ze startem systemu):

# systemctl start sssd //w dokumentacji jest service sssd start
# systemctl enable sssd //w dokumentacji jest chkconfig sssd on

Po tym zrestartowałbym system. Na końcu musimy zdefiniować kto może faktycznie się logować do swoich kont administracyjnych:

sudo realm deny -a
sudo realm permit --groups 'serba.local\Administratorzy domeny'

Na końcu dodamy grupę Administratorzy domeny do /etc/sudoers za pomocą visudo:

#%SERBA\\administratorzy\ domeny        ALL=(ALL:ALL) ALL #nieadekwatny do przykładu
#%administratorzy\ domeny@serba.local   ALL=(ALL:ALL) ALL #nieadekwatny do przykładu
%administratorzy\ domeny        ALL=(ALL:ALL) ALL

Na dobrą sprawę to tyle. GDM (menedżer wyświetlania w RHEL 8) nie wymaga dodatkowych modyfikacji, by umożliwić użytkownikom z AD logowanie się na swoje konta w interfejsie graficznym. Wspominając o Fortigate – z pewnego powodu agent FSSO nie widzi logowań na hostach z Linuksem, więc jeśli ktoś by wiedział jak to rozwiązać – zostawcie komentarz.

Jak sprawić, by z terminala korzystało się wygodniej?

Przeczytasz to w: 13 minut
Ładny PowerShell w Windowsie i ładny zsh w Linuksie. O tak!

Wbrew pozorom nie trzeba wiele, by zacząć lubić korzystanie z shella. Kilka prostych czynności może sprawić, że możemy wykonywać zadania szybciej, bo często zamiast wyklikać parę okienek możemy wykonać 1 polecenie, które za wszystko załatwia sprawę, lecz decydujemy się na te okienka, bo w końcu już kiedyś to klikaliśmy, to może w trakcie się jakoś przypomni jak to się robiło…nie?

Zmiany, o których będę pisał niżej sprawią, że to, co widzimy w terminalu będzie też przyjaźniejsze dla oka. Niestety, czasami niektóre czynności czy dobór kolorów w tych oknach jest kiepski i to może sprawiać taki odpychający efekt od terminali. Niezależnie czy to jest Windows czy Linux.

Windows + PowerShell + oh-my-posh + PSReadLine = ❤

Tak, Windows też potrafi zaskoczyć obsługą terminala przez PowerShell. W sumie to piszę tego posta, bo właśnie zaskoczył mnie. Od lat korzystam z dobroci zsh i nie miałem okazji mieć takich pozytywnych wrażeń w Windowsie, aż do teraz.

Zacznijmy od Chocolatey – to jest darmowe otwarto-źródłowe narzędzie, które jest menedżerem pakietów dla Windowsa. Działa ono tak samo jak menedżery pakietów w Linuksie, a ich założenie jest proste, na przykład menedżer apt (występuje w Ubuntu, Debianie i pochodnych) instaluje pakiet poprzez polecenie apt install gparted (instaluje program GParted). W Chocolatey instaluje się programy tak samo, na przykład Notepad++ instaluje się poleceniem choco install notepadplusplus.

Instalacja jest prosta – wykonaj te polecenie w Windows PowerShell z uprawnieniami administratora:

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

I voilà – mamy zainstalowane Chocolatey. Zainstalujmy więc tego Notepada++ w ten sposób, co opisałem powyżej:

choco install notepadplusplus

Na dobrą sprawę to musiałem tylko kilka razy zatwierdzić i gotowe:

Sprawmy, by ten shell wyglądał trochę lepiej. Zainstalujemy do tego conemu poleceniem choco install conemu:

PS C:\Users\Administrator> choco install conemu
Chocolatey v0.10.15
Installing the following packages:
conemu
By installing you accept licenses for the packages.
Progress: Downloading ConEmu 19.10.12.0... 100%

ConEmu v19.10.12.0 [Approved]
conemu package files install completed. Performing other installation steps.
The package ConEmu wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Note: To confirm automatically next time, use '-y' or consider:
choco feature enable -n allowGlobalConfirmation
Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint): y

Downloading ConEmu 64 bit
  from 'https://github.com/Maximus5/ConEmu/releases/download/v19.10.12/ConEmuSetup.191012.exe'
Progress: 100% - Completed download of C:\Users\Administrator\AppData\Local\Temp\chocolatey\ConEmu\19.10.12.0\ConEmuSetup.191012.exe (6.86 MB).
Download of ConEmuSetup.191012.exe (6.86 MB) completed.
Hashes match.
Installing ConEmu...
ConEmu has been installed.
  conemu may be able to be automatically uninstalled.
 The install of conemu was successful.
  Software installed as 'exe', install location is likely default.

Chocolatey installed 1/1 packages.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

Następnie zainstalujemy moduły z projektu oh-my-posh, który jest odpowiednikiem oh-my-zsh, lecz dla Windowsa:

Install-Module posh-git -Scope CurrentUser
Install-Module oh-my-posh -Scope CurrentUser

Jak widać, to nie było skomplikowane:

PS C:\Users\Administrator> Install-Module posh-git -Scope CurrentUser

NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact with NuGet-based repositories. The NuGet
 provider must be available in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\Administrator\AppData\Local\PackageManagement\ProviderAssemblies'. You can also install the NuGet provider by
 running 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install
and import the NuGet provider now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its
InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from
'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): y
PS C:\Users\Administrator> Install-Module oh-my-posh -Scope CurrentUser

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its
InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from
'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): y

Teraz możesz wykonać polecenie Set-Prompt i masz możliwość korzystania z oh-my-posh. Jeśli polecenie się nie wykonało, najprawdopodobniej nie masz zdefiniowanej polityki względem wykonywania skryptów powershellowych (Get-ExecutionPolicy daje wynik Undefined). Zmień tą politykę na Unrestricted poleceniem Set-ExecutionPolicy Unrestricted. Dzięki temu polityka zmieni się jedynie dla komputera z którego jest wykonywane te polecenie:

Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser       Undefined
 LocalMachine    Unrestricted

Moduł posh-git wymaga zainstalowanego gita, warto go zainstalować poleceniem choco install git:

C:\Users\Administrator> choco install git
Chocolatey v0.10.15
Installing the following packages:
git
By installing you accept licenses for the packages.
Progress: Downloading git.install 2.25.1... 100%
Progress: Downloading git 2.25.1... 100%

git.install v2.25.1 [Approved]
git.install package files install completed. Performing other installation steps.
The package git.install wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Note: To confirm automatically next time, use '-y' or consider:
choco feature enable -n allowGlobalConfirmation
Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint): a

Using Git LFS
Installing 64-bit git.install...
git.install has been installed.
git.install installed to 'C:\Program Files\Git'
  git.install can be automatically uninstalled.
Environment Vars (like PATH) have changed. Close/reopen your shell to
 see the changes (or in powershell/cmd.exe just type `refreshenv`).
 The install of git.install was successful.
  Software installed to 'C:\Program Files\Git\'

git v2.25.1 [Approved]
git package files install completed. Performing other installation steps.
 The install of git was successful.
  Software install location not explicitly set, could be in package or
  default install location if installer.

Chocolatey installed 2/2 packages.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

Teraz zaimportujmy sobie polecenia z tych modułów, które zainstalowaliśmy i odpalmy w końcu nasz nowy shell:

Import-Module posh-git
Import-Module oh-my-posh
Set-PoshPrompt -Theme Agnoster

W efekcie dostajemy to:

Trochę to odbiega od tego, co widać na moim początkowym zrzucie ekranu, więc popracujemy nad tym, by wyglądem się to nie różniło. Na początku musimy zainstalować czcionki Nerd Font. Znajdziemy je w tym ogromnym repozytorium czcionek. Czcionki Nerd Font różnią się od swoich oryginalnych odpowiedników tym, że mają dodanych kilka znaków, które sprawiają, że ten schemat (nazywający się Agnoster) wygląda lepiej. Ja osobiście bardzo lubię czcionkę Ubuntu Mono w terminalu i z niej też skorzystam. Jeśli podoba Ci się wygląd terminala jak w screenshocie nagłówkowym, zrób to samo co ja (opisałem poniżej):

Wejdź na tą podstronę repozytorium, otwórz folder Regular, następnie complete, i pobierz czcionkę Ubuntu Mono Nerd Font Complete Windows Compatible.ttf. Powtórz to dla folderów Regular-Italic, Bold i Bold-Italic. Jak pobierzesz wszystkie, zaznacz czcionki, kliknij na jedną PPM i wybierz Zainstaluj dla wszystkich użytkowników.

Następnie w oknie Windows PowerShell klikamy na pole tytułowe PPM i Właściwości. W zakładce Czcionka wybieramy naszą nową czcionkę i rozmiar. W moim przypadku to jest UbuntuMono NF z rozmiarem 16.

W ten sposób shell już wygląda lepiej:

Nadal, on może wyglądać lepiej. Zmienimy nieco kolorystykę tego okna, bo jednak ten niebieski trochę razi w oczy. Jeden z najpopularniejszych tematów znalazłem tutaj, w tym repozytorium. My skorzystamy z tematu Solarized-Dark. Instalacja jest prosta: na samym początku klonujemy repozytorium (przed pójściem dalej zrestartowałem terminal, bo nie miał świadomości tego, że ja już zainstalowałem gita):

git clone https://github.com/neilpa/cmd-colors-solarized
cd cmd-colors-solarized
reg.exe import .\solarized-dark.reg
.\Update-Link.cmd "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"
.\Update-Link.cmd "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell (x86).lnk"

Okej, teraz otwórz PowerShella jeszcze raz. Voilà, kolory zmienione! Ale nie ma tego nowego wyglądu shella, dlaczego? Dlatego, bo nie zdefiniowaliśmy go w profilu shella. Profil shella to nic innego jak prosty skrypt, który wykonuje się, gdy otwieramy terminal. Zanim zapiszemy sobie do niego to, co potrzebujemy to chciałem pokazać jeszcze jedną rzecz, która moim zdaniem jest niezbędna.

W terminalu niesamowicie istotną rzeczą jest autouzupełnianie składni polecenia. Robi się to naciskając tabulator (przycisk Tab). Naciśnięcie powoduje autouzupełnienie polecenia jeśli, następne naciśnięcia zmienią nasze polecenie na następną opcję, np. jeśli jest polecenie Restart- i my wciśniemy tabulator to za pierwszym razem otrzymamy pierwszą propozycję uzupełnionego polecenia, za drugiem drugą opcję (jeśli istnieje) i tak dalej. Problem w tym, że w jednym czasie widzisz tylko 1 polecenie, bo to jest domyślne ustawienie w PowerShella. Wygodniej by było widzieć opcje i nawet sterować strzałkami, by wybrać interesujące dla nas rozwiązanie. Mało tego, jeszcze lepiej będzie jeśli od razu przy tym wszystkim będziemy mieli drobną podpowiedź jakie np. parametry są dostępne w danym poleceniu czy też jakie wartości oczekują dane parametry. Naszym remedium jest te polecenie:

Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete

Dzięki niemu propozycje autouzupełnienia polecenia widzimy tak:

Okej, jak już mamy takie fajne ustawienia to zapiszmy sobie je tak, by wyświetlały się na stałe, co?

Okej, by otworzyć edycję profilu, z którego korzystamy w PowerShellu wykonaj polecenie:

if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force } .$env:SystemRoot/System32/notepad.exe $PROFILE

Wklejmy do niego to, co nas interesuje:

Dzięki temu teraz już od razu uruchamia się nam ten nowy wygląd shella:

Zmienialiśmy czcionki w oknie PowerShella, ale powinniśmy je też zmienić w Wierszu polecenia. Klikamy prawym na tytuł okna, następnie Właściwości.

Następnie podobnie jak poprzednio w zakładce Czcionka zmieniamy czcionkę na tą, którą wybraliśmy z serii Nerd Font (w moim przypadku to UbuntuMono NF) i dajemy okej. W ten sposób możemy się cieszyć ładnym wyglądem terminala w Windowsie. Te zmiany dotyczą głównie wyglądu, ale myślę, że najważniejszym przy nauce jakiegokolwiek terminala jest nauka obsługi skrótów klawiaturowych. To one sprawiają, że piszemy w nim coraz szybciej dzięki czemu nasza efektywność rośnie.

Na koniec zostawię Wam w postaci zajawki ciekawy wykład na temat szybkiej obsługi PowerShella z użyciem PSReadLine, naprawdę mi się bardzo podobał:

Linux + zsh + oh-my-zsh = ❤

Co prawda mowa tutaj o Linuksie, ale nie każdego Linuksa obsługuje się z poziomu Linuksa – w końcu serwery często nie mają zainstalowanego interfejsu graficznego i obsługuje się je poprzez SSH (secure shell). Tam też warto sprawić, by pracowało nam się z nim wygodnie.

Domyślnym interpreterem poleceń w Linuksie w dzisiejszych czasach jest Bash (/bin/bash), a w tych starszych lub w okrojonych dystrybucjach sh (/bin/sh). Mają one pewne możliwości, ale też ograniczenia konfiguracyjne, przez co na codzień korzystam z zsh (/bin/zsh). Nie jest on w standardzie w systemach (przynajmniej nie spotkałem się z dystrybucją mającą ją jako domyślny shell, choć jest on dostępny w MacOS (na ten moment korzystałem tylko z 10.15 i tam był). Pokażę tutaj jak zainstalować zsh oraz w jaki sposób można z niego zrobić fajny użytek.

UWAGA: instrukcje poniżej są ogólne dla wszystkich dystrybucji Linuksa, ale są polecenia, które są specyficzne dla dystrybucji (np. w Debianie/Ubuntu menedżerem pakietów jest apt/apt-get, w Arch Linuksie jest pacman, w Red Hat/CentOS/Fedora yum/dnf, a w Gentoo…w sumie to, co chcesz, ale przeważnie Portage (polecenie emerge). Weź pod uwagę też to, że nazwy pakietów w repozytoriach mogą się różnić.

Zaczynamy od instalacji gita, zsh i podkreślania składni zsh

sudo apt install git zsh zsh-syntax-highlighting -y

Okej, teraz odpalmy one-liner, którym zainstalujemy zsh:

sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Następnie musimy zatwierdzić zmianę shella na zsh i jesteśmy w domu.

--2020-03-15 11:47:42--  https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
Translacja raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.192.133, 151.101.128.133, ...
Łączenie się z raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... połączono.
Żądanie HTTP wysłano, oczekiwanie na odpowiedź... 200 OK
Długość: 8445 (8,2K) [text/plain]
Zapis do: `STDOUT'

-                   100%[===================>]   8,25K  --.-KB/s    w 0s       

2020-03-15 11:47:42 (215 MB/s) - zapisano na standardowe wyjście [8445/8445]

Cloning Oh My Zsh...
Cloning into '/home/supra/.oh-my-zsh'...
remote: Enumerating objects: 1137, done.
remote: Counting objects: 100% (1137/1137), done.
remote: Compressing objects: 100% (1102/1102), done.
remote: Total 1137 (delta 22), reused 926 (delta 17), pack-reused 0
Receiving objects: 100% (1137/1137), 750.06 KiB | 2.13 MiB/s, done.
Resolving deltas: 100% (22/22), done.

Looking for an existing zsh config...
Using the Oh My Zsh template file and adding it to ~/.zshrc.

Time to change your default shell to zsh:
Do you want to change your default shell to zsh? [Y/n] y
Changing the shell...
Hasło: 
Shell successfully changed to '/usr/bin/zsh'.

         __                                     __
  ____  / /_     ____ ___  __  __   ____  _____/ /_
 / __ \/ __ \   / __ `__ \/ / / /  /_  / / ___/ __ \
/ /_/ / / / /  / / / / / / /_/ /    / /_(__  ) / / /
\____/_/ /_/  /_/ /_/ /_/\__, /    /___/____/_/ /_/
                        /____/                       ....is now installed!


Please look over the ~/.zshrc file to select plugins, themes, and options.

p.s. Follow us on https://twitter.com/ohmyzsh

p.p.s. Get stickers, shirts, and coffee mugs at https://shop.planetargon.com/collections/oh-my-zsh

➜  ~ 

Tak czy siak ten shell jeszcze wymaga drobnych poprawek (przynajmniej w moim przekonaniu). Dodałbym lub zmieniłbym następujące linijki:

export TERM=xterm-256color

Dzięki temu możemy wykorzystywać więcej kolorów (256 zamiast 8), gdy korzystamy z SSH. Naprawdę bardzo przydatne, przynajmniej ja dzięki temu mam ładnego Vima, a o tym później. Tej linijki nie ma, musimy ją dodać.

ZSH_THEME="agnoster"

W tym polu definiujemy styl terminala, czyli jak on wygląda. Możemy korzystać z motywów, które są w oh-my-zsh, możemy ściągać niestandardowe, a możemy też tworzyć własne.

Niżej mamy też sekcję pluginów, w której możemy po prostu wzbogacić nasz shell o dodatkowe polecenia (ja dodałem polecenia do systemd, ufw i dockera, bo od pewnego czasu z niego korzystam):

plugins={
   git
   systemd
   ufw
   docker-compose
   docker-machine
   docker
)

Następnie dodajmy syntax highlighting do naszego shella, które zainstalowałem wcześniej:

source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

Dzięki temu shell zmienia kolor poleceń na czerwono, gdy są nieprawidłowe i usuwa podkreślenia ze ścieżek, gdy są nieprawidłowe:

Ponadto dodałbym to:

blk=$'\x1b[90m' # Sets text to black
red=$'\x1b[31m' # Sets text to red
grn=$'\x1b[92m' # Sets text to green
ylw=$'\x1b[93m' # Sets text to yellow
blu=$'\x1b[94m' # Sets text to blue
pur=$'\x1b[95m' # Sets text to purple
cyn=$'\x1b[96m' # Sets text to cyan
wht=$'\x1b[97m' # Sets text to white
rst=$'\x1b[0m'  # resets to default terminal color
bindkey "\033[1~" beginning-of-line
bindkey "\033[4~" end-of-line
export EDITOR="/usr/bin/vim"

Te polecenia ustawiają kolor shella w terminalu graficznym (czyli pracując w trybie bez interfejsu graficznego bezpośrednio na maszynie), poza tym te polecenia bindkey są fixem na niedziałające przyciski Home/End w niektórych środowiskach. Na koniec dodałem zmienną EDITOR i wartością jest ścieżka do Vima, bo to jest edytor tekstu, z którego korzystam najczęściej. Poza tym możemy też ustawić na koncie root wykorzystywanie zsh wykonując polecenia:

sudo chsh -s /bin/zsh root
sudo cp ~/.zshrc /etc/zsh/zshrc

Poprawa wyglądu terminala w interfejsie graficznym Linuksa

W efekcie końcowym nasz shell wygląda tak:

Niezbyt fajnie. By to poprawić musimy tak samo jak w Windowsie zainstalować odpowiednie czcionki. Możemy posłużyć się czcionkami, które też tam wykorzystaliśmy, czyli z repozytorium Nerd Font. Tak samo jak poprzednio posłużę się czcionkami dla Ubuntu Mono:

#!/bin/bash
mkdir -p ~/.local/share/fonts
wget https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/UbuntuMono/Regular/complete/Ubuntu%20Mono%20Nerd%20Font%20Complete.ttf -P ~/.local/share/fonts/
wget https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/UbuntuMono/Regular-Italic/complete/Ubuntu%20Mono%20Italic%20Nerd%20Font%20Complete.ttf -P ~/.local/share/fonts/
wget https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/UbuntuMono/Bold/complete/Ubuntu%20Mono%20Bold%20Nerd%20Font%20Complete.ttf -P ~/.local/share/fonts/
wget https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/UbuntuMono/Bold-Italic/complete/Ubuntu%20Mono%20Bold%20Italic%20Nerd%20Font%20Complete.ttf -P ~/.local/share/fonts/
fc-cache -f -v

Sprawdźmy, czy czcionki się pojawiły w naszym systemie dzięki poleceniu fc-list | grep "Nerd":

/home/supra/.local/share/fonts/Ubuntu Mono Bold Italic Nerd Font Complete.ttf: UbuntuMono Nerd Font:style=Bold Italic
/home/supra/.local/share/fonts/Ubuntu Mono Bold Nerd Font Complete.ttf: UbuntuMono Nerd Font:style=Bold
/home/supra/.local/share/fonts/Ubuntu Mono Nerd Font Complete.ttf: UbuntuMono Nerd Font:style=Regular
/home/supra/.local/share/fonts/Ubuntu Mono Italic Nerd Font Complete.ttf.1: UbuntuMono Nerd Font:style=Italic
/home/supra/.local/share/fonts/Ubuntu Mono Bold Italic Nerd Font Complete.ttf.1: UbuntuMono Nerd Font:style=Bold Italic
/home/supra/.local/share/fonts/Ubuntu Mono Italic Nerd Font Complete.ttf: UbuntuMono Nerd Font:style=Italic
/home/supra/.local/share/fonts/Ubuntu Mono Nerd Font Complete.ttf.1: UbuntuMono Nerd Font:style=Regular

Jak widać jest wszystko okej, dlatego zmieńmy sobie czcionkę na nową w taki sposób, jak przedstawiłem na animacji:

Pozostają jedynie te kiepskie kolory. Te możemy zmienić za pomocą gotowych plików, które możemy znaleźć na tym blogu. Z faktu, że w różnych środowiskach graficznych są różne programy pełniące rolę emulatora terminala (w moim ulubionym Xfce4 jest to xfce4-terminal), metoda na zmianę jest inna i pokażę jak to się robi w Xfce. Skorzystamy z tematu Solarized Dark, jak w przykładzie z PowerShellem.

#!/bin/bash
git clone https://github.com/sgerrand/xfce4-terminal-colors-solarized.git
mkdir ~/.config/Terminal
cp xfce4-terminal-colors-solarized/dark/terminalrc ~/.config/Terminal/

Następnie musimy w ustawieniach wybrać ten motyw i to tyle. Ja dodatkowo zmieniam sobie kolor zielonego na trochę bardziej przypominający zielony, bo tak po prostu lubię.

Poprawa wyglądu terminala w konsoli tekstowej Linuksa

Zsh działa per konto użytkownika, co oznacza, że będzie nam działać niezależnie czy połączymy się przez emulator terminala, fizyczny terminal czy SSH, lecz z drugiej strony my w motywie wykorzystujemy czcionki z niestandardowymi znakami, dlatego też pokażę Wam jak skorzystać z tych czcionek w terminalu i jak sprawić, by działały one z automatu.

Na początku musimy pobrać czcionki, które nas interesują. Ja korzystam z pogrubionych czcionek Terminus, bo po prostu takie mi się podobają. Możemy je też znaleźć w repozytorium Powerline. Warto zaznaczyć, że te czcionki muszą być w formacie .psf, a nie .ttf. Możemy pobrać i umieścić wszystkie czcionki za pomocą jednego prostego skryptu:

#!/bin/bash
sudo wget https://github.com/powerline/fonts/raw/master/Terminus/PSF/ter-powerline-v{12n,14b,14n,14v,16b,16n,16v,18b,18n,20b,20n,22b,22n,24b,24n,28b,28n,32b,32n}.psf.gz -P /usr/share/consolefonts/

Teraz musimy wybrać czcionkę, która nam się podoba bardziej. Nic bardziej prostego, robimy to poleceniem setfont /usr/share/consolefonts/<nazwa-pliku>, na przykład:

setfont /usr/share/consolefonts/ter-powerlinev16b.psf.gz

W ten sposób pojawi nam się nowa czcionka (przy okazji tutaj pokazuję jak można łatwo uzupełniać opcję tabulatorem w terminalu, gdy ma się zsh):

Na samym końcu sprawimy, że taka czcionka będzie na każdym terminalu w naszym komputerze i to będzie się działo automatycznie po restartach. Musimy edytować plik /etc/default/console-setup, zmieniamy tutaj wartości pól CODESET, FONTFACE i FONTSIZE. Ogólnie pliki czcionek są wczytywane w składni pliku <CODESET>-<FONTFACE><FONTSIZE>.psf.gz, dlatego też w <FONTFACE> na końcu lub w <FONTSIZE> na początku trzeba dopisać myślnik. Poniżej uzupełniłem plik względem pliku czcionki, który wykorzystywałem powyżej.

# CONFIGURATION FILE FOR SETUPCON

# Consult the console-setup(5) manual page.

ACTIVE_CONSOLES="/dev/tty[1-6]"

CHARMAP="UTF-8"

CODESET="ter"
FONTFACE="powerline-"
FONTSIZE="v16b"

VIDEOMODE=

# The following is an example how to use a braille font
# FONT='lat9w-08.psf.gz brl-8x8.psf'

Po zmienieniu tego pliku można sprawdzić efekt wykonując polecenie setupcon. Jeśli czcionka się zmieniła poprawnie to po restarcie też się zmieni. Tutaj też chciałbym podziękować Tenebreosowi za znalezienie ominięcia problemu w poleceniu setupcon w nazwach plików, naprawdę to się przydało!

Poprawa wyglądu terminala w SSH

Na koniec część dla tych, którzy administrują serwerami Linuksa zdalnie, przez SSH. Pewnie większość z Was korzysta z PuTTY. Ja akurat korzystam z trochę bardziej wypasionej wersji, która nazywa się KiTTY i można ją pobrać tutaj.

Zaczniemy od zmiany kolorów terminala. Docelowo ma wyglądać jak te wszystkie poprzednie oraz będzie korzystał z tej samej czcionki (Ubuntu Font NF), co w sekcji z ustawianiem czcionek dla PowerShella. Zamiast wyklikiwać w opcjach wszystkie kolory, możemy zastosować ten jeden pliczek, który za nas zrobi całą robotę, poniżej zawartość:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\9bis.com\KiTTY\Sessions\Default%20Settings]
"Colour0"="131,148,150"
"Colour1"="147,148,161"
"Colour2"="0,43,54"
"Colour3"="7,54,66"
"Colour4"="0,43,54"
"Colour5"="238,232,213"
"Colour6"="7,54,66"
"Colour7"="0,43,56"
"Colour8"="220,50,47"
"Colour9"="203,75,22"
"Colour10"="0,187,0"
"Colour11"="88,255,117"
"Colour12"="181,137,0"
"Colour13"="101,123,131"
"Colour14"="38,139,210"
"Colour15"="131,148,150"
"Colour16"="211,54,130"
"Colour17"="108,113,196"
"Colour18"="42,161,152"
"Colour19"="147,161,161"
"Colour20"="238,232,213"
"Colour21"="253,246,227"
"Colour22"="187,187,187"
"Colour23"="0,0,0"
"Colour24"="0,0,0"
"Colour25"="187,0,0"
"Colour26"="0,187,0"
"Colour27"="187,187,0"
"Colour28"="0,0,187"
"Colour29"="187,0,187"
"Colour30"="0,187,187"
"Colour31"="187,187,187"
"Colour32"="0,0,0"
"Colour33"="187,187,187"

Poza tym warto zmienić w profilu domyślnym czcionkę, więc otwierając ustawienia w sekcji Window > Appearance, w sekcji Font settings klikamy przycisk Change… i wybieramy czcionkę, którą chcemy ustawić. Na zrzucie poniżej macie jak to wygląda u mnie:

Następnie musimy taką zmianę zapisać, najlepiej to zrobić w domyślny profilu (Sekcja Session), klikamy nazwę sesji i przycisk Save:

Gotowe. W ten sposób mamy shell przygotowany do pracy: