背景:在做一個安裝指令碼,期間會執行一些資料庫的操作,需要DBA帳號才可以執行。 我們用的JSCH建立SSH通道,直接連接到目標機器上執行,效果和開啟命令列是一樣的,唯一特殊的,就是關於DBA的密碼的問題。 Oracle(我們的資料庫用的Oracle)的指令碼中是提供了連同密碼一起輸入的功能的,但是!凡事就怕但是!客戶提出的要求是:對帳號密碼的明文儲存零容忍! Ok,說白了,不能在設定檔裡把DBA密碼寫進去,然後批量執行。必須在Oracle'提示輸入密碼的時候,輸入之。 問題:JSCH提供的原始的幾個channel,還是比較直接的。 常用的有SFTP/ChannelShell/ChannelExec。為了取環境變數方便,我們用了ChannelShell。 ChannelShell是可以設定InputStream和OutputStream的。 但是輸入密碼只能從console輸入,所以channelshell.setInputStream(System.in)嗎? 但是其他命令是從設定檔輸入的,所以channelshell.setInputStream(new FileInputStream(filename))嗎? 無論如何,只能設定一個InputStream,怎麼兼顧? 調查:第一步,google之。 有幾個文章參考了,但是不合適。 第二步,嘗試使用Except4J,不過它也是全指令碼的,不能中間切換到System.in. 第三步,就是按照Except4J的做法,自己控制JSCH的input/output stream。 於是有了此文。 方案:前面說了那麼多廢話,其實目的就是一個:把來龍去脈介紹一下,或許有大俠發現我幹了個重複的事情,有更好的方案,可以給我指教一下。 如果也被這個問題困擾的話,可以看看,一起討論下。 我的方法就是: 自己寫InputStream和OutputStream,然後把它們設定到JSCH的channelshell裡去,這樣它就會從我這裡讀寫了 然後呢,讀的時候就從我的檔案裡讀,我告訴它輸入是“xyz”它就拿到xyz; 寫的時候呢,它就寫到我的outputstream裡,我就知道結果是ABC啦。 有了以上兩個前提,那麼我再加一些小功能: 1. 讀檔案的時候,我多寫一些配置資訊,發現現在是password,那我就從System.in讀資料,然後發給JSCH channel; 2. 獲得response的時候,我判斷是否和我期望的結果一樣,然後我再執行下一條。 於是就有了這個設定檔: [java] [html] ## This file format just for POC, you can define yours. ## For my format, it is: ## 1. # starts for comments ## 2. There are 3 parts: [<expect>]<type>[<content>] ## 3. For <expect>, it's easy: [$] means you expect a '$' ends; ## 4. For <type>, support 'send' and 'password'. ## If 'send', means the <content> will be send to SSH channel. ## If 'password', means the <content> come from system console, that is, need you type in. [$]send[pwd] [$]send[whoami] [$]send[su - root] [Password:]password[] [#]send[pwd] [#]send[ls] [#]send[whoami] [#]send[exit] [$]send[ls] [$]send[pwd] [$]send[whoami] [$]send[su - root] [Password:]password[] [#]send[pwd] [#]send[ls] [#]send[whoami] [#]send[exit] [$]send[exit] 原理就是這樣了,很簡單的苦力活。