2019年2月26日火曜日

postfix main.cf smtpd_sender_restrictions

最近、メールサーバでキューを確認すると、やたらと???@0000.comへのバウンスメールが溜まっている。
中身を確認すると、PICほにゃららというファイル名で難読化したJavaScriptが添付されているメールです。
何が目的なのか分かりませんが、ごみメール送ってきてバウンスも返せないので、受信したらそのまま破棄したいと思います。
main.cf
smtpd_sender_restrictions = reject_unknown_sender_domain,
                            check_sender_access regexp:/etc/postfix/sender_restrictions
sender_restrictions
/@[0-9]{4}\.com$/ DISCARD
ログ見ると
Feb 26 14:30:26 web1 postfix/smtpd[17797]: NOQUEUE: discard: RCPT from unknown
[aaa.bbb.ccc.ddd]: <Deena96@0334.com>: Sender address triggers DISCARD action; 
from=<Deena96@0334.com> to=<abc@example.com> 
proto=SMTP helo=<[aaa.bbb.ccc.ddd]>
上手く行っているようです。

2018年11月30日金曜日

postfix - postsrsdでOutBoundsMailだけを対象に書き換えたい

DMZにゲートウエイメールサーバが置いてあり、main.cfのtransport_mapsで振り分けして内部メールサーバに転送しています。postsrsdをインストールして普通に設定するとインバウンドメールも書き換えられてしまいます。対処方法としては、もう1セット別ポート(10003番ポート)にsmtpdを立ててインバウンドメールを1つ目のtrivial-rewriteで送ったあと外向きのメールを2つ目のcleanupで書き換えてやります。master.cfは下記のようになります。
master.cf(一部)
(略)
cleanup   unix  n       -       n       -       0       cleanup
  -o recipient_canonical_maps=tcp:localhost:10002
  -o recipient_canonical_classes=envelope_recipient

(略)

rewrite   unix  -       -       n       -       -       trivial-rewrite
  -o default_transport=smtp:[127.0.0.1]:10003

(略)

127.0.0.1:10003 inet  n       -       n       -       -       smtpd
  -o cleanup_service_name=cleanup2
cleanup2   unix  n       -       n       -       0       cleanup
  -o sender_canonical_maps=tcp:localhost:10001
  -o sender_canonical_classes=envelope_sender
  -o queue_service_name=qmgr2
qmgr2      unix  n       -       n       300     1       qmgr
  -o rewrite_service_name=rewrite2
rewrite2   unix  -       -       n       -       -       trivial-rewrite

2018年11月7日水曜日

VisualBasic6(VB6)Format, IsDateの新元号対応

業務システムでは今でもVB6使っているのが残っています。きっとMSさんが対応してくれると思ってはいますが、心配なのでオーバーライド関数を作ってみました。
レジストリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras
を反映するように作成してあります。

modFormatOverride.bas
Attribute VB_Name = "modFormatOverride"
Option Explicit

Private Const HKEY_LOCAL_MACHINE = &H80000002
Private varEnumEras As Variant

' 新元号対応IsDate関数
Public Function IsDate(expression As Variant) As Boolean

    If vba.IsDate(expression) Then
        IsDate = True
        Exit Function
    End If
    IsDate = vba.IsDate(ConvertAD(expression))

End Function

' 新元号対応Format関数
Public Function Format(expression As Variant, Optional fmtstr As Variant = "", Optional firstdayofweek As Variant = vbSunday, Optional firstweekofyear As Variant = vbUseSystem) As String

    Dim i As Integer, intYear As Integer
    Dim varDef As Variant, varExp As Variant, varTmpfmt As Variant
    
    If Not IsDate(expression) Then
        Format = vba.Format(expression, fmtstr, firstdayofweek, firstweekofyear)
        Exit Function
    End If

    varExp = ConvertAD(expression)

    varDef = Array("General Date", "Long Date", "Medium Date", "Short Date", "Long Time", "Medium Time", "Short Time")
    
    For i = 0 To UBound(varDef)
        If LCase(fmtstr) = LCase(varDef(i)) Then
            Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
            Exit Function
        End If
    Next
    
    If InStr(LCase(fmtstr), "g") = 0 And InStr(LCase(fmtstr), "e") = 0 Then
        Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
        Exit Function
    End If

    For i = 0 To UBound(varEnumEras)
        If CDate(varExp) < varEnumEras(i)(0) Then
            Exit For
        End If
    Next
    i = i - 1

    If i > 3 Then
        varTmpfmt = Replace(Replace(fmtstr, "g", "z"), "G", "z")
        varTmpfmt = Replace(Replace(varTmpfmt, "e", "x"), "E", "x")
        varTmpfmt = Replace(varTmpfmt, ".", "v")
        varTmpfmt = vba.Format(varExp, varTmpfmt, firstdayofweek, firstweekofyear)
        varTmpfmt = Replace(varTmpfmt, "v", ".")
        varTmpfmt = Replace(varTmpfmt, "zzz", varEnumEras(i)(1)(0))
        varTmpfmt = Replace(varTmpfmt, "zz", varEnumEras(i)(1)(1))
        varTmpfmt = Replace(varTmpfmt, "z", varEnumEras(i)(1)(3))
        intYear = Year(varExp) - Year(varEnumEras(i)(0)) + 1
        varTmpfmt = Replace(varTmpfmt, "xx", Right("0" & intYear, 2))
        Format = Replace(varTmpfmt, "x", intYear)
    Else
        Format = vba.Format(varExp, fmtstr, firstdayofweek, firstweekofyear)
    End If

End Function

' 新元号文字列を西暦文字列に変換
Private Function ConvertAD(expression As Variant) As Variant

    Dim i As Integer, j As Integer, k As Integer
    Dim objRegistry As Object
    Dim strKeyPath As String, strChar As String
    Dim varEras As Variant, varValue As Variant, varNum As Variant

    ConvertAD = expression
    
    If IsEmpty(varEnumEras) Then
        Set objRegistry = GetObject("winmgmts:\root\default:StdRegProv")
        strKeyPath = "SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"
        objRegistry.EnumValues HKEY_LOCAL_MACHINE, strKeyPath, varEras
        ReDim varValue(UBound(varEras))
        ReDim varEnumEras(UBound(varEras))
        For i = 0 To UBound(varEras)
            objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, varEras(i), varValue(i)
            varEras(i) = CDate(Replace(varEras(i), " ", "/"))
            varValue(i) = Split(varValue(i), "_")
            varValue(i)(2) = LCase(varValue(i)(3))
            varValue(i)(3) = UCase(varValue(i)(3))
            varEnumEras(i) = Array(varEras(i), varValue(i))
        Next
        Set objRegistry = Nothing
    End If
    
    If Not vba.IsDate(expression) Then
        For i = 4 To UBound(varEnumEras)
            For j = 0 To UBound(varEnumEras(i)(1))
                If InStr(Trim(expression), varEnumEras(i)(1)(j)) = 1 Then
                    For k = InStr(expression, varEnumEras(i)(1)(j)) + Len(varEnumEras(i)(1)(j)) To Len(expression)
                        strChar = Mid(expression, k, 1)
                        If InStr("年/,-", strChar) > 0 Then
                            Exit For
                        Else
                            varNum = varNum & strChar
                        End If
                    Next
                    If IsNumeric(varNum) Then
                        ConvertAD = Replace(expression, varEnumEras(i)(1)(j) & varNum, Year(varEnumEras(i)(0)) + varNum - 1)
                        Exit Function
                    End If
                End If
            Next
        Next
    End If

End Function
まあ、CDate("新元号1年5月1日")みたいにCDateに直接新元号を入れられるとだめですけどね...

2018年11月2日金曜日

Adobe Acrobat 8(J)でAdobe PDF 印刷設定が英語表示になる場合の直し方

64bitのシステムだとなるようです。
Program Files(x86)\Adobe\Acrobat 8.0\Acrobat\Adist.JPN
をコピーして同じフォルダでAdist64.JPNという名前にすれば日本語になります。

2018年10月24日水曜日

Rainloopをちょっとだけ日本語対応してみた

1.メール一覧の日付表示を「D M月.」から「M月D日」に変更します。

1.12.1/static/js/app.js
1.12.1/static/js/admin.js
1.12.1/static/js/min/app.min.js
1.12.1/static/js/min/admin.min.js
return e.format("D MMM.") → return e.format("MMMDo")

2.テキスト罫線で飾ったメールの縦ずれが起きるので、'MS ゴシック'を追加します。

1.12.1/static/css/app.css, 1.12.1/static/css/min/app.min.css
font-family:にmonospaceが設定されている全ての先頭に'MS ゴシック',を挿入

3.iso-2022-jpでの機種依存文字(①②③やⅠⅡⅢなど)の文字化け対策

/usr/share/rainloop/rainloop/v/1.12.1/app/libraries/MailSo/Base/Utils.php
500行目(ConvertEncoding)に以下を挿入
case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::ISO_2022_JP):
  if (\MailSo\Base\Utils::IsIconvSupported())
  {
    $sResult = \MailSo\Base\Utils::IconvConvertEncoding($sResult, 'iso-2022-jp-ms', $sToEncoding);
  }
  else if (\MailSo\Base\Utils::IsMbStringSupported())
  {
    $sResult = \MailSo\Base\Utils::MbConvertEncoding($sResult, 'iso-2022-jp-ms', $sToEncoding);
  }
  $sResult = (false !== $sResult) ? $sResult : $sInputString;
  break;
iso-2022-jpからエンコードするときiso-2022-jp-msを指定してやります。
同様に sjis → sjis-win や euc-jp → eucjp-win もできると思います。

4.日本語対応じゃないけど、sieveで複数個所に転送したいので、stop;をコメント化します。

1.12.1/app/libraries/RainLoop/Providers/Filters/SieveStorage.php
433行目をコメント化
   case \RainLoop\Providers\Filters\Enumerations\ActionType::FORWARD:
    $sValue = $oFilter->ActionValue();
    if (0 < \strlen($sValue))
    {
     if ($oFilter->Keep())
     {
      $aCapa['fileinto'] = true;
      $aResult[] = $sTab.'fileinto "INBOX";';
     }

     $aResult[] = $sTab.'redirect "'.$this->quote($sValue).'";';
 //    $aResult[] = $sTab.'stop;';
    }
    else
    {
     $aResult[] = $sTab.'# @Error (redirect): empty action value';
    }
    break;

5.Ver.1.13.0にしたらドロップダウンメニューのアイコンがずれるので、CSSを変更します。 app.min.css で .dropdown-menu a の display:block; を display:flex; に変更

2018年9月21日金曜日

Fail2banで永久banしたい(CentOS7 firewallcmd-ipset)

昔、GmailはGoogleのメールサーバから全く別のメールアドレスでメールを送信する設定が出来ました。それが、暗号化してないとダメになって、いつの間にかドメインが違うと登録できなくなっていました。昔に設定した既得権でずっと使えていたのですが、つい最近、手違いで設定解除してしまいました。仕方がないので、PostfixにCyrus SASLでSMTP-AUTHを導入しました。数時間後にmaillogを見ると、「SASL LOGIN authentication failed」の嵐になっていました。こういう輩には速攻で、永久にお引き取り願おうと思っております。というわけで、今回はCentOS7+Fail2ban(firewallcmd-ipset)の設定をしていきます。
まずは、インストールします。
# yum install --enablerepo=epel -y fail2ban fail2ban-systemd
次に、/etc/fail2ban/jail.localを作成します。このファイルはjail.confをオーバーライドするものです。
jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 172.16.1.0/24
maxretry = 5
findtime = 3600
bantime  = 86400
backend  = systemd
usedns   = yes

[postfix-sasl]
enabled  = true
findtime = 86400
bantime  = -1
port     = smtp,465,submission
logpath  = %(postfix_log)s
bantimeにマイナスを設定すると永久banになるようです。
早速、起動と行きたいところですが、このままでは上手く動きません。
ipsetのtimeoutにbantimeを入れる動作をするためにエラーになってしまいます。0が永久ですが、bantimeに0入れるとfail2banがban & unbanを繰り返します。
また、ログが更新されると再起動した時にログ落ちしたIPはbanされませんので、追加されるたびに別のファイル(下記では、permanent_bans.ip)に残しておき、起動時にそのファイルから再度、読み込みします。
これを変更するには/etc/fail2ban/action.d/firewallcmd-ipset.confのactionstartとactionbanを編集します。
firewallcmd-ipset.conf(抜粋)
#actionstart = ipset create fail2ban-<name> hash:ip timeout <bantime>
#              firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>

actionstart = ipset create fail2ban-<name> hash:ip timeout 0
              firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
              cat /etc/fail2ban/permanent_bans.ip | awk '/^fail2ban-<name> / {print $2}' | while read IP; do ipset add fail2ban-<name> $IP timeout 0 -exist; done

actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
             ipset flush fail2ban-<name>
             ipset destroy fail2ban-<name>

#actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
actionban = ipset add fail2ban-<name> <ip> timeout 0 -exist
            echo "fail2ban-<name> <ip>" >> /etc/fail2ban/permanent_bans.ip
また、blocktypeは相手に応答しないdropにします。
iptables-common.conf(抜粋)
#blocktype = REJECT --reject-with icmp-port-unreachable
blocktype = DROP
後は起動するだけです。
# systemctl start fail2ban
# systemctl enable fail2ban
banのリストを見るには、
# ipset list
unbanしたいときは、/etc/fail2ban/permanent_bans.ip から該当のipを削除して
# fail2ban-client set postfix-sasl unbunip <ip_addr>
という感じです。

2018年9月20日木曜日

Let's Encrypt で取得したワイルドカード証明書をIISサーバで使いたい


ワイルドカード証明書が取得できましたので、それを使って外部から参照できないWindowsのIISサーバにインストールおよび自動更新をしていきたいと思います。
まずWindowsに証明書をインストールするには、PEM(.pem)形式からPKCS12(.pfx)形式に変換する必要があります。変換にはopensslを使用します。証明書が更新されたときに実行されるスクリプトcertbot-deploy.shに下記を追加します。
openssl pkcs12 -export -in /etc/letsencrypt/live/example.com/fullchain.pem -inkey /etc/letsencrypt/live/example.com/privkey.pem -out /etc/letsencrypt/pfx/example.com/fullchain.pfx -passout file:/etc/letsencrypt/pfx/pass.txt
/etc/letsencryptにpfxディレクトリ、/etc/letsencrypt/pfxにexample.comディレクトリを作成して、任意のパスワードを書いたpass.txtを作成して入れておきます。
# cd /etc/letsencrypt
# mkdir pfx
# cd pfx
# echo password > pass.txt
# mkdir example.com
証明書が更新され上記が実行されると/etc/letsencrypt/pfx/example.com/fullchain.pfxが作成されます。
Windows側にファイルを移す方法はいくつかありますが今回はweb経由で転送します。
VirtualHostにAlias /pfx /etc/letsencrypt/pfx/example.comを追加して、/etc/httpd/conf.d/pfx.confを作成します。
pfx.conf
<Directory /etc/letsencrypt/pfx/example.com/>
    <IfModule mod_authz_core.c>
        Require ip 172.16.1.0/24
    </IfModule>
</Directory>
Require ipで内部からのみ許可するようにします。
Windowsにはwgetが標準ではありませんので、Wget for Windowsをインストールします。インストールしたら実行ファイルにパスを通しておきます。
環境変数pathにC:\Program Files\GnuWin32\bin;を追加します。
cmd.exeを起動して,
D:\letsencrypt>wget https://www.example.com/pfx/fullchain.pfx --no-check-certificate -N
とするとダウンロードできます。
ダウンロードしたら証明書をインストールします。インストールには、certutilコマンドを使います。
D:\letsencrypt>certutil -f -p password -importpfx fullchain.pfx
とするとインストールできます。後は、IISマネージャからバインドすれば有効になるはずです。

更新ですが3か月毎に手動更新するのは大変なのでbatファイルを作成してタスクスケジューラで毎日1回実行することにします。私が管理しているのはIIS6とIIS8があります。IIS6では、appcmd.exeがありませんので、設定をエクスポートして置換してからインポートし直しています。エクスポートしたファイルはUTF-8です。コードページの変更とかが面倒ですので、置換にはmfindを使わせてもらっています。
renew_cert_iis8.bat
@echo off
set url=https://www.example.com/pfx/
set passwd=password
set file1=fullchain.pfx
set file2=fullchain.live.pfx
set cn=*.example.com

setlocal ENABLEDELAYEDEXPANSION

echo * DownloadFile
wget %url%%file1% --no-check-certificate -N

echo * CheckFile
set timestamp1=
set timestamp2=
for %%a in (%file1%) do set timestamp1=%%~ta
for %%b in (%file2%) do set timestamp2=%%~tb
if "%timestamp1%" == "%timestamp2%" (
    echo Not Renew Cert
) else (
    if "%timestamp1%" gtr "%timestamp2%" (
        echo Renew Cert

        echo * Import Cert
        certutil -f -p %passwd% -importpfx %file1%
        copy %file1% %file2% > nul

        echo * SSL CertHash
        set n=0
        for /f "tokens=2,* usebackq" %%a in ( `certutil -store my %cn%^| findstr /c:"Cert ハッシュ(sha1)"` ) do (
          set CERTHASH[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        for /f "tokens=1,2 usebackq" %%a in ( `certutil -store my %cn%^| findstr /c:"この日以前: "` ) do (
          set CERTDATE[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        set t1=0000/00/00
        set t2=0000/00/00
        :BEGIN
        call set dt=%%CERTDATE[!n!]%%
        if defined dt (
          if !t1! leq !dt! (
            set t2=!t1!
            set n2=!n1!
            set t1=!dt!
            set n1=!n!
          ) else (
            if !t2! leq !dt! (
              set t2=!dt!
              set n2=!n!
            )
          )
          set /a n=n+1
          goto BEGIN
        )
        call set NEWHASH=%%CERTHASH[%n1%]: =%%
        call set OLDHASH=%%CERTHASH[%n2%]: =%%
        echo NEWHASH=%NEWHASH% [NotAfter: %t1%]
        echo OLDHASH=%OLDHASH% [NotAfter: %t2%]

        echo * Rewrite CertHash
        %SystemRoot%\System32\inetsrv\appcmd.exe renew binding /oldcert:%OLDHASH% /newcert:%NEWHASH%
        echo Update done
    ) else (
        echo Not Renew Cert
    )
)
renew_cert_iis6.bat
@echo off
set url=https://www.example.com/pfx/
set passwd=password
set cn=*.example.com
set file1=fullchain.pfx
set file2=fullchain.live.pfx
set file3=iiscnfg.xml
set site1=/lm/w3svc/1
set site2=w3svc/1


setlocal ENABLEDELAYEDEXPANSION

echo * DownloadFile
wget %url%%file1% --no-check-certificate -N

echo * CheckFile
set timestamp1=
set timestamp2=
for %%a in (%file1%) do set timestamp1=%%~ta
for %%b in (%file2%) do set timestamp2=%%~tb
if "%timestamp1%" == "%timestamp2%" (
    echo Not Renew Cert
) else (
    if "%timestamp1%" gtr "%timestamp2%" (
        echo Renew Cert

        echo * Import Cert
        certutil -f -p %passwd% -importpfx %file1%
        copy %file1% %file2% > nul

        echo * SSL CertHash
        set n=0
        for /f "tokens=2,* usebackq" %%a in ( `certutil -store -v my %cn%^| findstr /c:"Cert ハッシュ(sha1)"` ) do (
          set CERTHASH[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        for /f "tokens=1,2 usebackq" %%a in ( `certutil -store -v my %cn%^| findstr /c:"この日以前: "` ) do (
          set CERTDATE[!n!]=%%b
          set /a n=n+1
        )
        set n=0
        set t1=0000/00/00
        set t2=0000/00/00
        :BEGIN
        call set dt=%%CERTDATE[!n!]%%
        if defined dt (
          if !t1! leq !dt! (
            set t2=!t1!
            set n2=!n1!
            set t1=!dt!
            set n1=!n!
          ) else (
            if !t2! leq !dt! (
              set t2=!dt!
              set n2=!n!
            )
          )
          set /a n=n+1
          goto BEGIN
        )
        call set NEWHASH=%%CERTHASH[%n1%]: =%%
        call set OLDHASH=%%CERTHASH[%n2%]: =%%
        echo NEWHASH=%NEWHASH% [NotAfter: %t1%]
        echo OLDHASH=%OLDHASH% [NotAfter: %t2%]

        echo * Export Settings
        del /q %file3% 2> nul
        iiscnfg /export /f %file3% /sp %site% /inherited /children

        echo * Rewrite CertHash
        mfind /W /E8 /%OLDHASH%/%NEWHASH%/l %file3%

        echo * Import Setting
        iiscnfg /import /f %file3% /sp %site1% /dp %site1% /inherited /children
        del /q %file3% 2> nul

        echo * Restart IIS
        iisweb /start %site2%
        del %file2%
        copy %file1% %file2% > nul
    ) else (
        echo Not Renew Cert
    )
)

postfix main.cf smtpd_sender_restrictions

最近、メールサーバでキューを確認すると、やたらと???@0000.comへのバウンスメールが溜まっている。 中身を確認すると、PICほにゃららというファイル名で難読化したJavaScriptが添付されているメールです。 何が目的なのか分かりませんが、ごみメール送ってきてバウン...