TeraTerm SCP バッチ(MD5 ハッシュ値比較あり)

【概要】
Windosのバッチから、TeraTermマクロを起動してLinuxとWindows間でファイルをSCP(送受または受信)します。
送信先と送信元でファイルのMD5ハッシュ値を取得し、比較して送信成功を判定します。

※新しいWindowsでは、TeraTermを使用しなくてもコマンドプロンプトからSCPが可能です。
 「コマンドプロンプト SCP バッチ (ハッシュ値比較あり)」(https://ttbe.jp/cmd_scp_bat2/)をご参照ください。

【動作環境】
Windows側:Windows10
Linux側:CentOS7.4
Teraterm4.82以降のTeraTermマクロ
※CentoOS6、Windows7 でもおそらく動作します

【作成手順】
1.任意のフォルダ名でフォルダを作成します。
2.テキストエディタ(メモ帳など)を開きます。
3.「【scp_winlin.bat】」の内容をテキストに貼り付けます。

  ※コメントに日本語を使用しているため、文字コードにご注意ください
4.以下の箇所を更新します。

REM 記載例("C:\Users\testuser\Desktop\scp_test\test.txt")
set WIN_FILE="<Windows側ファイルのフルパス>" 
REM Teratermマクロプログラム(ttpmacro.exe)のフルパス
set TTPM_FILE="C:\Program Files (x86)\teraterm\ttpmacro.exe"

6.送信もしくは受信の設定をします。
・ファイルをWindowsからLinuxに送る場合

 「[Linux to Windows]」の行をコメントアウト(行頭に「REM 」付加)

REM SCP(Windows→Linux)
echo %date% %time% INFO: SCP Start[Windows to Linux] >> %BAT_LOGFILE%
REM SCP(Linux→Windows)
REM echo %date% %time% INFO: SCP Start[Linux to Windows] >> %BAT_LOGFILE%

・ファイルをLinuxからWindowsに送る場合

 「[Windows to Linux]」の行をコメントアウト(行頭に「REM 」付加)

REM SCP(Windows→Linux)
REM echo %date% %time% INFO: SCP Start[Windows to Linux] >> %BAT_LOGFILE%
REM SCP(Linux→Windows)
echo %date% %time% INFO: SCP Start[Linux to Windows] >> %BAT_LOGFILE%

6.作成したテキストを、作成したフォルダにファイル名「scp_winlin.bat」で保存します。
7.テキストエディタ(メモ帳など)を開きます。
8.「【scp_winlin.ttl】」の内容をテキストに貼り付けます。
9.以下の箇所を更新します。

IPADDR = '<Linux側IPアドレス>'
USERNAME = '<Linux側ユーザ名>'
; 記載例('C:\Users\testuser\Desktop\scp_test\test.txt')
SEND_FILE = '<Windows側ファイルフルパス>'
; 記載例('/tmp/test.txt')
RECV_FILE = '<Linux側ファイルフルパス>'

10.送信もしくは受信の設定をします。
・ファイルをWindowsからLinuxに送る場合

 「scprecv LIN_FILE WIN_FILE」の行をコメントアウト(行頭にセミコロン「;」付加)

; SCPでファイル送信(Windows → Linux)
;=====================================================
scpsend WIN_FILE LIN_FILE
;=====================================================
; SCPでファイル受信(Linux → Windows)
;=====================================================
;scprecv LIN_FILE WIN_FILE
;=====================================================

・ファイルをLinuxからWindowsに送る場合

 「scpsend WIN_FILE LIN_FILE」の行をコメントアウト(行頭にセミコロン「;」付加)

; SCPでファイル送信(Windows → Linux)
;=====================================================
;scpsend WIN_FILE LIN_FILE
;=====================================================
; SCPでファイル受信(Linux → Windows)
;=====================================================
scprecv LIN_FILE WIN_FILE
;=====================================================

11.パスワードファイルを使用しない場合は、以下を更新
※パスワードは暗号化されてファイルに保存されますが、ファイル自体をコピーされるセキュリティリスクがあります。
セキュリティ強化のため、「【セキュリティ強化手順】」を参照して接続元IPアドレスの制限などを行ってください。
以下の箇所をコメントアウト(行頭にセミコロン「;」付加)

PASSWORD_FILE = 'pw.txt'
getpassword PASSWORD_FILE USERNAME PASSWORD

以下の箇所のコメントアウトを解除(行頭のセミコロン「;」削除)

;passwordbox 'Password' 'Get password'
;PASSWORD = inputstr

12.作成したテキストを、作成したフォルダにファイル名「scp_winlin.ttl」で保存します。

【実行手順】
1.「scp_winlin.bat」をダブルクリックして実行します。
※動かなくなったように見える後、しばらく待機(30秒ほど)すると自動でウィンドウが消えてスクリプトが終了します。

2.「scp_winlin.bat」と同じフォルダにある「scp_winlin_bat.log.txt」をテキストエディタで開き、実行した時間と、以下表示があることを確認します。
※エラーの場合は別のエラーメッセージが表示されます

・「MD5 check OK. File SCP Complete. 」
・「Script End. 」

【scp_winlin.bat】

@echo off
REM ###################################################
REM ### Windowsバッチ Windos-Linuxファイル送受信用
REM ###################################################
REM Windows側ファイルのフルパス
REM 記載例("C:\Users\testuser\Desktop\scp_test\test.txt")
set WIN_FILE="<Windows側ファイルのフルパス>" 
REM Teratermマクロプログラム(ttpmacro.exe)のフルパス
set TTPM_FILE="C:\Program Files (x86)\teraterm\ttpmacro.exe"

REM TeraTermマクロファイルのフルパス
set TTL_FILE="%~dp0scp_winlin.ttl"

REM バッチログファイルのフルパス
set BAT_LOGFILE="%~dp0scp_winlin_bat.log.txt"

REM TeraTermマクロの出力したログファイルのフルパス
set LIN_MD5_FILE="%~dp0scp_winlin_ttl_log.txt"

REM カレントディレクトリをバッチのディレクトリへ移動
cd /d %~dp0

REM SCP(Windows→Linux)
echo %date% %time% INFO: SCP Start[Windows to Linux] >> %BAT_LOGFILE%
REM SCP(Linux→Windows)
REM echo %date% %time% INFO: SCP Start[Linux to Windows] >> %BAT_LOGFILE%

REM TTLファイル存在確認
if not exist %TTL_FILE% (
echo %date% %time% ERROR: File not found.[%TTL_FILE%] >> %BAT_LOGFILE%
exit /b
)

REM TeraTermマクロ実行
%TTPM_FILE% %TTL_FILE%
if %errorlevel% neq 0 (
echo %date% %time% ERROR: Execution error[ttpmacro.exe] >> %BAT_LOGFILE%
exit /b
)

REM MD5チェック用サブルーチン実行
REM (引数1:バッチログファイルパス、引数2:Windows側ファイルパス、
REM 引数3:TeraTermマクロの出力したログファイルパス)
REM ※引数は全体で半角2047文字以内であること
call :MD5_CHECK %BAT_LOGFILE% %WIN_FILE% %LIN_MD5_FILE%

exit /b

REM ### MD5ハッシュチェック用サブルーチン ###
:MD5_CHECK
set WIN_FILE_NAME=%~nx2
set LIN_MD5_FILE_NAME=%~nx3

REM ローカルのWindows側ファイルのMD5ハッシュ値を取得
for /f "usebackq tokens=1 delims=;" %%i in (`certutil -hashfile %2 MD5 ^| findstr /v "MD5 CertUtil:"`) do (
set WIN_MD5=%%i
)

REM 半角スペースが含まれる場合は削除
set WIN_MD5=%WIN_MD5: =%

REM TeraTermマクロの出力したログファイルの存在確認
if not exist %3 (
echo %date% %time% ERROR: File not found.[%3] >> %1
exit /b
)

REM TeraTermマクロの出力したログから、Linux側ファイルのMD5ハッシュを取得
for /f "usebackq tokens=1" %%j in (`findstr %WIN_FILE_NAME% %3 ^| findstr /v "date.*md5sum"`) do (
set LIN_MD5=%%j
)

REM TeraTermマクロの出力したログをリネーム
REM ※時刻は1桁の場合空白が含まれるので、「0」に置換
set time2=%time: =0%
rename %3 %LIN_MD5_FILE_NAME%_%date:~0,4%%date:~5,2%%date:~8,2%%time2:~0,2%%time2:~3,2%

REM Windows側ファイルのMD5ハッシュが取得できなかった場合
if "%WIN_MD5%"=="" (
echo %date% %time% ERROR: Send file MD5 get error. >> %1
exit /b
)

REM Linux側ファイルのMD5ハッシュが取得できなかった場合
if "%LIN_MD5%"=="" (
echo %date% %time% ERROR: Recieve file MD5 get error. >> %1
exit /b
)

REM MD5が等しかった場合
if "%WIN_MD5%"=="%LIN_MD5%" (
echo %date% %time% INFO: MD5 check OK. File SCP Complete. >> %1
REM MD5が等しくない場合
) else (
echo %date% %time% ERROR: MD5 check NG. File SCP Faild. >> %1
)

REM ログにMD5ハッシュの値を記録
echo %date% %time% INFO: Windows file MD5 :%WIN_MD5% >> %1
echo %date% %time% INFO: Linux file MD5 :%LIN_MD5% >> %1

echo %date% %time% INFO: Script End. >> %1

exit /b

【scp_winlin.ttl】

; ### Teratemマクロ Windos-Linuxファイル送受信用 ###
; Linux側IPアドレス
LIN_IPADDR = '<Linux側IPアドレス>'
; Linux側ユーザ名
LIN_USERNAME = '<Linux側ユーザ名>'
; Windows側ファイルフルパス
; 記載例('C:\Users\testuser\Desktop\scp_test\test.txt')
WIN_FILE = '<Windows側ファイルフルパス>'
; Linux側ファイルフルパス
; 記載例('/tmp/test.txt')
LIN_FILE = '<Linux側ファイルフルパス>'
; ファイル名に日付を使用する場合の例
;getdate FILENAMEDATE '%y%m%d.txt'
;strconcat WIN_FILE FILENAMEDATE 
; 接続ポート(通常は22)
PORT = '22'

; TeraTermマクロのログファイル名(Windows側)
TTL_LOG_FILE_NAME='scp_winlin_ttl_log.txt'

; タイムアウトを15秒に設定
timeout = 15

; Linux接続時にパスワードファイルを使用する場合
; ※パスワードファイルを使用せず、手動でアカウント情報を入力する場合は、
;  下記コメントアウト
; ※パスワードは暗号化されてファイルに保存されるが、ファイル自体を
;  コピーされるセキュリティリスクがあるので注意
; ※パスワードファイルが存在しない場合(初回)は、
;  インプットボックスが表示される。入力後にファイルが作成される。
; ※パスワードファイルは、ttlファイルと同じパスに作成される。
;  別の場所をフルパスで指定することも可能
; ※パスワードの入力を失敗した場合は「PASSWORD_FILE」のファイルを削除
; ;=====================================================
PASSWORD_FILE = 'pw.txt'
getpassword PASSWORD_FILE LIN_USERNAME PASSWORD
; ;=====================================================

; Linux接続時に手動でアカウント情報を入力する場合
; ※パスワードファイルを使用する場合は、下記コメントアウト
; ;=====================================================
;inputbox 'User:' 'Login'
;LIN_USERNAME = inputstr
;passwordbox 'Password' 'Get password'
;PASSWORD = inputstr
; ;=====================================================

; SSH接続コマンド生成
COMMAND = LIN_IPADDR
strconcat COMMAND ':'
strconcat COMMAND PORT
strconcat COMMAND ' /ssh /auth=password /user='
strconcat COMMAND LIN_USERNAME
strconcat COMMAND ' /passwd='
strconcat COMMAND PASSWORD

; SSH接続
connect COMMAND

; 接続できない場合処理終了
if result <> 2 then
end
endif

; タイムアウト時間内にプロンプトが表示されない場合処理終了
wait '$' '#'
if result = 0 then
disconnect 0
end
endif

; SCPでファイル送信(Windows → Linux)
;=====================================================
scpsend WIN_FILE LIN_FILE
;=====================================================
; SCPでファイル受信(Linux → Windows)
; ;=====================================================
;scprecv LIN_FILE WIN_FILE
; ;=====================================================

; ファイルSCPプロセス確認コマンド生成
COMMAND = 'ps -ef | grep "'
strconcat COMMAND LIN_FILE
strconcat COMMAND '" | grep -v grep | grep -wc scp'

; ループ最大回数(変更可能)
ROOP_MAX = 1000
ROOP_COUNT = 0

; ループ処理
:grep_roop
; ループカウント加算
ROOP_COUNT = ROOP_COUNT + 1
; 待機(ミリ秒)(変更可能)
mpause 3000
; ファイル送信プロセス確認
sendln COMMAND
; エコーバックを読み捨てる
recvln
; 実行結果を取得
recvln
; 実行結果を数値に変換して変数に格納
str2int GREP_COUNT inputstr

; プロセスが存在しない場合はループ終了
if GREP_COUNT = 0 then
goto grep_roop_end
else
; ループ最大回数を超えた場合はループ終了
if ROOP_MAX < ROOP_COUNT then
goto grep_roop_end
else
goto grep_roop
endif
endif
:grep_roop_end

; Windows側のカレントフォルダをttlファイルのフォルダ移動
getdir WIN_DIR
changedir WIN_DIR

; ログファイルを開く
fileopen logfile TTL_LOG_FILE_NAME 0
; 同期モードに変更
setsync 1

; Linux側ファイルのMD5生成コマンド生成
COMMAND = 'date && md5sum '
strconcat COMMAND LIN_FILE

; 一行分の文字が受信された場合、システム変数 result に1が格納される。
; そうでない場合 result に0が格納される
result=1

; Linux側ファイルのMD5生成コマンド実行
sendln COMMAND

while result=1
; 一行受信
recvln
; ログファイルに記載
filewriteln logfile inputstr
endwhile

; 非同期モードに変更
setsync 0

; exitコマンド送信
sendln 'exit'

; TeraTermマクロ終了
end

【セキュリティ強化手順(CentOS7の場合)】
下記の手順で、以下を行います。
1.SCP用のユーザは一般のSSHポート経由での接続を禁止
2.SCP専用ポートを指定し、SCP用ユーザかつ、特定のIPからの接続のみ可能にする
3.一般ユーザからrootユーザにスイッチできるユーザを制限

※sshd_configのForceCommandは設定していませんので、一般ユーザでの
SSH操作が可能です(シェル実行など)
※sshd_configのChrootDirectoryは設定していませんので、
一般ユーザが操作できる場所はすべて操作できます。

1.SCP用のユーザは一般のSSHポート経由での接続を禁止
(1)TeratermでSSH接続
「su -」コマンドでrootユーザにスイッチ

(2)下記コマンドで、SCP接続用の一般ユーザを作成
例:「useradd scponlyuser」
※以降表示されるコマンドの「#」は入力不要です

# useradd <scp用に作成するユーザのユーザ名></scp用に作成するユーザのユーザ名>

(3)下記コマンドで、作成したユーザにパスワード付加

# passwd <作成したユーザ名>

(4)SSH接続確認
別途Teratermからscponlyuserで接続できることを確認し、
「exit」コマンドで抜ける

(5)下記コマンドでsshdの設定ファイル(sshd_config)をバックアップ

# cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config_`date +"%Y%m%d"`

(6)下記コマンドでバックアップファイル作成を確認

# ls -l /etc/ssh/sshd_config_`date +"%Y%m%d"`

(7)sshd_config編集
※ssh_configではないので注意
(ssh_configはSSHクライアント設定)

(8)下記コマンドでファイルをviエディタで編集

# vi /etc/ssh/sshd_config

「i」キー押下してエディットモードに変更し、「#Port 22」以下に下記2行追記

Port 22
Port 8022

末尾に以下を追記

Match LocalPort 22
DenyUsers scponlyuser
Match LocalPort 8022
AllowUsers scponlyuser

「Esc」キー押下してコマンドモードに変更し、「:wq」入力後、「Enter」キー押下してファイル保存。

(9)下記コマンドでSSHDを再起動して設定反映

# systemctl restart sshd

(10)下記コマンドで、22番ポートと8022ポートがLISTENしているか確認

# ss -lnt

2.SCP専用ポートを指定し、SCP用ユーザかつ、特定のIPからの接続のみ可能にする
(1)下記コマンドでfirewalldの、現在のゾーン設定の確認

# firewall-cmd -get-default-zone

例:「firewall-cmd –info-zone=public」

# firewall-cmd -info-zone=<現在のデフォルトゾーン>

(2)下記コマンドでゾーン設定追加
下記コマンドで、8022ポートの接続元を、特定のIPのみに変更
例:「firewall-cmd –permanent –zone=public –add-rich-rule=”rule family=”ipv4″ source address=”192.168.0.5/32″ port protocol=”tcp” port=”8022″ accept”」

# firewall-cmd -permanent -zone=<現在のデフォルトゾーン> -add-rich-rule="rule family=ipv4 source address=<接続元として許可するIPアドレス>/32 port protocol=tcp port=8022 accept"

「success」表示を確認

(3)下記コマンドで設定再読み込み

# firewall-cmd -reload

「success」表示を確認

(4)下記コマンドで変更後確認
例:「firewall-cmd –info-zone=public」

# firewall-cmd -info-zone=<現在のデフォルトゾーン>

(5)「【scp_winlin.bat】」をテキストエディタで開き、下記を更新して保存する。
更新前:

; 接続ポート(通常は22)
PORT = '22'

更新後:

; 接続ポート(通常は22)
PORT = '8022'

3.一般ユーザからrootユーザにスイッチできるユーザを制限
※この設定を行うと、wheelグループに所属しない一般ユーザは
rootにスイッチできなくなるので注意!!

(1)下記コマンドでrootにスイッチ可能なユーザユーザを設定
※ここで設定しないユーザはrootにスイッチできないので注意
※登録ユーザが無い場合は、事前に「useradd <ユーザ名>」新規に作成し、
「passwd <ユーザ名>」コマンドでパスワード付加しておく

# usermod -G wheel <rootにスイッチ可能かつ、ssh接続可能なユーザ></rootにスイッチ可能かつ、ssh接続可能なユーザ>

(2)下記コマンドで、グループ設定ファイルで設定変更を確認
(設定したユーザのユーザ名が追加されていること)

# grep wheel /etc/group

(3)下記コマンドで、/etc/pam.d/suバックアップ

# cp -p /etc/pam.d/su /etc/pam.d_`date +"%Y%m%d"`

(4)下記コマンドで、バックアップファイル作成を確認

# ls -l /etc/pam.d_`date +"%Y%m%d"`

(5)下記コマンドでファイルをviエディタで編集

# vi /etc/pam.d/su

下記の行コメントアウト「#」を削除(「#」の場所で「X」キー押下して1文字削除)
※「required」の行のみコメントアウト解除

#auth required pam_wheel.so use_uid

「:wq」入力後、「Enter」キー押下してファイル保存。

(6)rootにスイッチ可能なユーザでSSH接続し、「su -」コマンド実行。
rootにスイッチ可能なことを確認

(7)scp用の一般ユーザでSSH接続し、「su -」コマンド実行。
「su: 拒否されたパーミッション」と表示されることを確認

【セキュリティ強化手順(Windows側)】
バッチ実行ユーザの制限を行う場合の手順を記載しています。
ここでは、グループ「Administrators」のみアクセス可能にする設定を記載しています。

(1)「scp_winlin.bat」および、「scp_winlin.ttl」ファイルを格納しているフォルダを右クリックし、「プロパティ」を選択。

(2)「セキュリティ」タブを選択、「詳細設定」ボタンを押下

(3)「アクセス許可」タブにて、「継承の無効化」ボタン押下

(4)「現在継承されているアクセス許可で実行する処理」ウィンドウが開くので、「継承されたアクセス許可をこのオブジェクトの明示的なアクセス許可へ変換します。」を選択

(5)「アクセス許可エントリ」にて「Administrators」以外を削除
※ここで権限を制御します。「Administrators」以外を削除すると、
「Administrators」グループに参加していないユーザはアクセスできなくなるので注意してください!
※所属しているグループはコマンドプロンプト(Windowsキー+Rキー→「cmd」入力して「OK」)で「net user <ユーザ名>」コマンド実行で確認できます。