シェルスクリプト

2015年01月30日

このエントリーをはてなブックマークに追加

CVE-2015-0235: GHOST Buster シェルスクリプト #CentOS-6 | blog.hansode.orgのCentOS-7編。

CVE-2015-0235関連

RHEL-7 / CentOS-7 関連

glibcを入れ替える必要がある。

2015/01/30時点の対応

検証用にbuildワーカーを複数環境扱ってるので、それぞれ対応する必要があった。CentOS-7系に関しては7.0.1406のみで良いので対応は大分軽度だ。手順と動作を確認し、上手く行ったのが下記シェルスクリプト。

 ghost-buster-rhel7.sh

バージョン判定には、

  • /etc/yum/vars/releaseverが存在する場合は使用し、
  • 存在しない場合は/etc/centos-releaseから情報取得
#!/bin/bash
#
# requires:
#  bash
#
set -e
set -o pipefail
set -x

if [[ -f /etc/yum/vars/releasever ]]; then
  releasever=$(< /etc/yum/vars/releasever)
else
  releasever=$(
   sed \
    -e '/^CentOS /!d' \
    -e 's/CentOS.*\srelease\s*\([0-9][0-9.]*\)\s.*/\1/' \
    < /etc/centos-release
  )
fi

arch=$(arch)
case "${arch}" in
  i*86)   basearch=i386 arch=i686 ;;
  x86_64) basearch=${arch} ;;
esac

case "${releasever}" in
  7.0.1406)
    yum update  -y \
      glibc \
      glibc-common \
      glibc-devel \
      glibc-headers
    ;;
esac

対象環境で実行するとglibcが入れ替わる。

あとがき

手元に都合の良く手頃な検証環境があるのは幸せな事なのだろう。




編集
@hansode at 18:00|PermalinkComments(0)TrackBack(0)

2015年01月29日

このエントリーをはてなブックマークに追加

CVE-2015-0235関連

RHEL-6 / CentOS-6 関連

glibcを入れ替える必要がある。

2015/01/29時点の対応

検証用にbuildワーカーを複数環境扱ってるので、それぞれ対応する必要があった。updatesが反映されているのは6.6のみ。それ以下を放置する訳にもいかない。それゆえ、6.66.[0-5]と言う場合分けが必要だ。手順と動作を確認し、上手く行ったのが下記シェルスクリプト。

 ghost-buster-rhel6.sh

バージョン判定には、

  • /etc/yum/vars/releaseverが存在する場合は使用し、
  • 存在しない場合は/etc/centos-releaseから情報取得
#!/bin/bash
#
# requires:
#  bash
#
set -e
set -o pipefail
set -x

if [[ -f /etc/yum/vars/releasever ]]; then
  releasever=$(< /etc/yum/vars/releasever)
else
  releasever=$(
   sed \
    -e '/^CentOS /!d' \
    -e 's/CentOS.*\srelease\s*\([0-9][0-9.]*\)\s.*/\1/' \
    < /etc/centos-release
  )
fi

arch=$(arch)
case "${arch}" in
  i*86)   basearch=i386 arch=i686 ;;
  x86_64) basearch=${arch} ;;
esac

case "${releasever}" in
  6.6)
    yum update  -y \
      glibc \
      glibc-common \
      glibc-devel \
      glibc-headers
    ;;
  6.[0-5])
    expected_version=2.12-1.149.el6_6.5
    case "$(rpm -qa --qf '%{Version}-%{Release}\n' glibc)" in
      ${expected_version})
        ;;
      *)
        base_uri=http://ftp.jaist.ac.jp/pub/Linux/CentOS/6.6/updates/${basearch}/Packages
        yum install -y \
          ${base_uri}/glibc-${expected_version}.${arch}.rpm \
          ${base_uri}/glibc-common-${expected_version}.${arch}.rpm \
          ${base_uri}/glibc-devel-${expected_version}.${arch}.rpm \
          ${base_uri}/glibc-headers-${expected_version}.${arch}.rpm
        ;;
    esac
    ;;
esac

対象環境で実行するとglibcが入れ替わる。

あとがき

手元に都合の良く手頃な検証環境があるのは幸せな事か。

続きを読む


編集
@hansode at 21:30|PermalinkComments(0)TrackBack(0)

2013年07月01日

このエントリーをはてなブックマークに追加

世間では余り使われてないのか

test(1)コマンドによる変数の中身やファイル・ディレクトリの存在有無を確認する方法は、良く知られている気がする。しかし、functionに関して触れらてるエントリを見かけないので、ここに書いておく。

declareかtypesetの出番

declareとtypeset、どちらでも良い。同じ意味。自分は何となくな理由で declare を使っている。

declare -f [name]

サンプルコード

#!/bin/bash

function defined_func() { :; }

declare -f defined_func
echo $? # should be zero

declare -f undefined_func
echo $? # should be non-zero

実行結果は、こうなる。

defined_func ()
{
    :
}
0
1
結果まとめ
項目declare -f 実行結果終了ステータス
定義済み関数の内容0
未定義無し1

もしも関数の内容を表示させたくない場合は /dev/null へリダイレクトすれば良い。

declare -f [name] >/dev/null
使い所は?

declare -f [name] を上手く使うと、bashでDSLが可能になって来る。bashでDSLのネタを書く為の前提エントリとして書いたのが、本エントリ。次回、bash-DSLエントリをお楽しみに?

続きを読む


編集
@hansode at 13:00|PermalinkComments(0)TrackBack(0)

2013年06月30日

このエントリーをはてなブックマークに追加

個人見解: 大半は "$@" にしておけば、期待する動作となる

幾つかスクリプトを書いて来て、気を付けておいた方が良かったことの1つが、$@の扱い。$@ と "$@" は、内部処理では大きく違う。サンプルコードと結果を、まとめてみた。

dump-vers.sh

#!/bin/bash
#
# $ dump-vers.sh [args]
#

function dump_vers() {
  while [[ "$1" ]]; do
    echo "'$1'"
    shift
  done
}

echo '#1'; dump_vers $@
echo
echo '#2'; dump_vers "$@"

実行例1: " なし

$ ./dump-vers.sh a b c d
#1
'a'
'b'
'c'
'd'

#2
'a'
'b'
'c'
'd'
  • #1 引数4つ
  • #2 引数2つ

実行例2: " あり

$ ./dump-vers.sh "a b" "c d"
#1
'a'
'b'
'c'
'd'

#2
'a b'
'c d'
  • #1 引数4つ
  • #2 引数2つ
まとめ
引数#1#2
実行例1a b c d44
実行例2"a b" "c d"42

大半は "$@" にしておけば、期待する動作となる。

続きを読む


編集
@hansode at 15:00|PermalinkComments(0)TrackBack(0)

2011年09月12日

このエントリーをはてなブックマークに追加

参考比較: 単発curl v.s. 100分割curl

参考値とは言え、約21倍性能が増した。

内容所要時間
単発2,226秒
100分割103秒

ネットワーク帯域や検証マシンスペックによっては、もっと顕著な差が生まれるかも知れない。

検証内容
単発curl
$ time curl -s -L -o textinstall-134-x86.iso http://dlc.sun.com/osol/install/downloads/text_install/134/textinstall-134-x86.iso

real    37m6.561s
user    0m1.216s
sys     0m45.667s
100分割curl
$ time ./pararell-curl.sh http://dlc.sun.com/osol/install/downloads/text_install/134/textinstall-134-x86.iso
...(省略)...

real    1m43.885s
user    0m3.576s
sys     0m32.038s
検証環境
  • Ubuntu 10.04.3 LTS
  • bash 4.1.5
  • curl 7.19.7
レシピ
  1. 何並列で実行するのか決めておく。今回は100本。
  2. ダウンロード対象のContent-Length取得
  3. Content-Length値をもとに、curlコマンドの --range オプション でcurlコマンド毎に担当範囲を指定し、バックグラウンドジョブとして実行。

    man curlより

           -r/--range 
                  (HTTP/FTP/SFTP/FILE)  Retrieve a byte range (i.e a partial docu‐
                  ment) from a HTTP/1.1, FTP or  SFTP  server  or  a  local  FILE.
                  Ranges can be specified in a number of ways.
    
                  0-499     specifies the first 500 bytes
    
                  500-999   specifies the second 500 bytes
    
                  -500      specifies the last 500 bytes
    
                  9500-     specifies the bytes from offset 9500 and forward
    
                  0-0,-1    specifies the first and last byte only(*)(H)
    
                  500-700,600-799
                            specifies 300 bytes from offset 500(H)
    
                  100-199,500-599
                            specifies two separate 100-byte ranges(*)(H)
    
  4. 全ジョブが完了するまで待機
  5. 分割ダウンロードされたファイルを結合
ソースコード

レシピをもとにラッパースクリプトを作成。

使い方

第一引数を指定しない場合、CentOS 6.0のISOイメージがダウンロード対象となる。

$ git clone git://gist.github.com/1205668.git
$ ./pararell-curl.sh
$ ./pararell-curl.sh http://mirror.3tier.com/centos/6/isos/i386/CentOS-6.0-i386-bin-DVD.iso
参考文献
あと書き

分割によってこれほどの性能差が生まれるとは思っても見なかった。

続きを読む


編集
@hansode at 15:50|PermalinkComments(0)TrackBack(0)

2011年08月13日

このエントリーをはてなブックマークに追加

手短にオレオレ証明書を作れたら、楽になれる

開発作業をしていると、色々理由はあれど、年に数回、オレオレ証明書(自己署名証明書)が必要になる。 その度に、過去の作業記録を掘り起こしてopensslコマンドを実行。それの繰り返し。 今後の作業を考慮し、スクリプトを作成してgistにスクリプトを登録した。

検証環境
  • Ubuntu 10.04.3 Server LTS
  • OpenSSL 0.9.8k 25 Mar 2009
  • dash 0.5.5.1-3ubuntu2
要件定義

過去の作業を振り返り、何が必要なのかをまとめると下記の通り。

  • コモンネーム指定は必須
  • 連絡先メールアドレスを設定出来ると良い
  • 主要webサーバの設定例が表示されると良い
  • 登録者情報は不要。必要だった事がない。
スクリプトデザイン

実装するに辺り、下記のようにまとまる。

  • コマンド引数は1つか2つで良い
    • 必須: コモンネーム
    • 任意: メールアドレス
    • $ script common_name [email]
  • ファイル名にコモンネームを入れる
    • $(コモンネーム)_key.pem
    • $(コモンネーム)_csr.pem
    • $(コモンネーム)_crt.pem
  • 各pemファイルは、カレントディレクトリに生成・保存
  • apachenginxの設定例を出力
    • apache:
      
      SSLCertificateFile    /path/to/$(コモンネーム)_crt.pem
      SSLCertificateKeyFile /path/to/$(コモンネーム)_key.pem
      
    • nginx:
      
      ssl_certificate     /path/to/$(コモンネーム)_crt.pem;
      ssl_certificate_key /path/to/$(コモンネーム)_key.pem;
      
コモンネームを指定して実行

実際にスクリプトを実行してオレオレ証明書を生成してみると、下記の通りになる。

  • コモンネーム: ssl.example.com

実行結果:


$ ./gen-selfsigned-cert.sh ssl.example.com
...(省略)...

# 1. Generated a Private Key and CSR
=> ssl.example.com_key.pem

=> ssl.example.com_csr.pem

# 2. Generated a Self-Signed Certificate
=> ssl.example.com_crt.pem

# 3. Installing the Private Key and Certificate
# 4. Configuring SSL Enabled Virtual Hosts
-----
apache:
        SSLCertificateFile    /path/to/ssl.example.com_crt.pem
        SSLCertificateKeyFile /path/to/ssl.example.com_key.pem

nginx:
        ssl_certificate     /path/to/ssl.example.com_crt.pem;
        ssl_certificate_key /path/to/ssl.example.com_key.pem;
-----

生成されたファイル:


$ ls -1 *.pem
ssl.example.com_crt.pem
ssl.example.com_csr.pem
ssl.example.com_key.pem

後の作業は、

  1. pemをどこか適切な場所へ配置
  2. webサーバのconfigを変更
  3. webサーバにconfigを読み込ませる
  4. ブラウザから "https://ssl.example.com/" へHTTP接続して確認

あと書き

面倒臭い作業の1つを減らせてスッキリした。

ソースコード

gistにはブログ等にコードを埋め込む仕組みが用意されていて便利だ。

続きを読む


編集
@hansode at 10:00|PermalinkComments(0)TrackBack(0)

2010年04月13日

このエントリーをはてなブックマークに追加

例えばシステム起動時に runlevel=[0-5] を指定したい

▼検証環境

  • CentOS 5.4(i386)
  • Linux 2.6.18-164.15.1.el5xen

▼材料

  • /boot/grub/menu.list
  • /etc/rc.d/rc.sysinit
作業内容

▼/boot/grub/menu.list を修正

default=0
timeout=15
splashimage=(hd0,0)/grub/splash.xpm.gz
title CUI| CentOS (2.6.18-164.15.1.el5xen)
        root (hd0,0)
        kernel /xen.gz-3.4.0
        module /vmlinuz-2.6.18-164.15.1.el5xen ro root=/dev/sda3 quiet selinux=0 runlevel=3
        module /initrd-2.6.18-164.15.1.el5xen.img-cui
title GSB | CentOS (2.6.18-164.15.1.el5xen)
        root (hd0,0)
        kernel /xen.gz-3.4.0
        module /vmlinuz-2.6.18-164.15.1.el5xen ro root=/dev/sda3 quiet selinux=0 runlevel=5
        module /initrd-2.6.18-164.15.1.el5xen.img-gui

それぞれ、runlevel=? を追加


▼/etc/rc.d/rc.sysinit の行末に追記

> if strstr "$cmdline" runlevel=; then
>   for arg in $cmdline ; do
>     runlevel=${arg##runlevel=}
>     case "${runlevel}" in
>     3) # runlevel 3の場合
>       command...;
>       ;;
>     5) # runlevel 5の場合
>       command...;
>       ;;
>     esac
>   done
> fi
  • strstr関数は、/etc/init.d/functions で定義されている
  • 起動時に指定されたオプションは、/proc/cmdline に存在する
  • /proc/cmdlineは、/etc/rc.d/rc.sysinit内で「cmdline=$(cat /proc/cmdline)」として変数が用意されている



編集
@hansode at 22:05|PermalinkComments(0)TrackBack(0)

2010年04月01日

このエントリーをはてなブックマークに追加

getoptsは使わない

久しぶりにevalを使った。

▼extract-opts.sh


#!/bin/sh

opts=""

# extract opts
for arg in $*; do
  case $arg in
    --*=*)
      key=${arg%%=*}; key=${key##--}
      value=${arg##--*=}
      eval ${key}=${value}
      opts="${opts} ${key}"
      ;;
  esac
done

# dump opts
for opt in ${opts}; do
  eval echo ${opt} : \$${opt}
done

exit 0

▼実行例


$ ./extract-opts.sh --prefix=/opt/hansode --dist=debian --version=sid --size=10
prefix : /opt/hansode
dist : debian
version : sid
size : 10



編集
@hansode at 18:00|PermalinkComments(0)TrackBack(0)

2008年09月26日

このエントリーをはてなブックマークに追加

コマンドラインで連番のファイル名を作る から派生


月次の処理をしたい場合があるはず。
  • 一ヶ月分のファイル名を作る
  • 年と月を指定可能にする
こんな条件だと、コマン道ではこう書く。


$ year=2008; mon=10; for i in $(LC_ALL=C cal $mon $year | egrep -v '[a-z]'); do printf "access_log.%04d%02d%02d\n" $year $mon $i; done
access_log.20081001
access_log.20081002
access_log.20081003
access_log.20081004
access_log.20081005
access_log.20081006
access_log.20081007
access_log.20081008
access_log.20081009
access_log.20081010
access_log.20081011
access_log.20081012
access_log.20081013
access_log.20081014
access_log.20081015
access_log.20081016
access_log.20081017
access_log.20081018
access_log.20081019
access_log.20081020
access_log.20081021
access_log.20081022
access_log.20081023
access_log.20081024
access_log.20081025
access_log.20081026
access_log.20081027
access_log.20081028
access_log.20081029
access_log.20081030
access_log.20081031

分解して解説して行く


まずはcalコマンドの部分


$ year=2008; mon=10; LC_ALL=C cal $mon $year
    October 2008
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
LC_ALL=Cとして居るのは日本語表示されると都合が悪いからだ。
日本語だと「egrep -v '[a-z]'」で上手くフィルタ出来ない。


$ year=2008; mon=10; cal $mon $year | egrep -v '[a-z]'
     10月 2008
日 月 火 水 木 金 土
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

こうなる。
それに対し、LC_ALL=Cを入れると上手く行く。


$ year=2008; mon=10; LC_ALL=C cal $mon $year | egrep -v '[a-z]'
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

この通り。
数字だけ抜き出せた。



次はforループ

forのリスト部分は、改行かスペースを区切り文字として扱ってくれる。
whileとreadの組み合わせでは都合が悪い。

cal+egrepの結果をforのリストにする。


$ year=2008; mon=10; for i in $(LC_ALL=C cal $mon $year | egrep -v '[a-z]'); do echo $i; done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1日ずつ出て来た。




ループ内のprintf

あとはechoをprintfに変え、$yearと$monを含めて出力する。


$ year=2008; mon=10; for i in $(LC_ALL=C cal $mon $year | egrep -v '[a-z]'); do printf "access_log.%04d%02d%02d\n" $year $mon $i; done
access_log.20081001
access_log.20081002
access_log.20081003
access_log.20081004
access_log.20081005
access_log.20081006
access_log.20081007
access_log.20081008
access_log.20081009
access_log.20081010
access_log.20081011
access_log.20081012
access_log.20081013
access_log.20081014
access_log.20081015
access_log.20081016
access_log.20081017
access_log.20081018
access_log.20081019
access_log.20081020
access_log.20081021
access_log.20081022
access_log.20081023
access_log.20081024
access_log.20081025
access_log.20081026
access_log.20081027
access_log.20081028
access_log.20081029
access_log.20081030
access_log.20081031
出来上がり。



まとめ


  • calとegrepを組み合わせて日付リストを生成
  • forの特性を生かしてリストを分解
  • printfで出力を整形
さ〜て、Perlやzshではどう書くんだろうか?
ネタふりをしてみる。



編集
@hansode at 20:20|PermalinkComments(0)TrackBack(1)

2008年09月25日

このエントリーをはてなブックマークに追加

刺身さんのエントリが気になった


[Perl]Perl で連番のファイル名を作るより

seq とか jot とか、どっちがどっちか覚えられないし、 "001.txt" "002.txt" みたいに頭にゼロをつけることができるかどうかもよくわからないので Perl でやったほうが楽だ。
コマン道としては、こうかな。
printfコマンドを知っているかどうかがキモなのだと思う。


$ i=1; limit=13; while [ $i -le $limit ]; do j=$(printf "%03d" $i); echo access_log.200801$j; i=$(($i+1)); done
access_log.200801001
access_log.200801002
access_log.200801003
access_log.200801004
access_log.200801005
access_log.200801006
access_log.200801007
access_log.200801008
access_log.200801009
access_log.200801010
access_log.200801011
access_log.200801012
access_log.200801013
これは「access_log.$(printf "%03d" $i)」としても良い。
見づらいので上記例のようにした。



編集
@hansode at 17:55|PermalinkComments(3)TrackBack(2)