2007年03月21日

cat を使わずにテキストファイルを読み出す方法について

普通、テキストファイルの内容を表示する際には cat コマンドや less コマンドを使います。
例えば、 README を読む場合には、

cat README

のようにします。しかし、 cat コマンドや less コマンドが使えないという状況もあるかもしれません。(具体的には、プログラム自体が存在しなかったり、強制アクセス制御により実行が禁止されているといったケースです。)そんな時でも、 bash を実行することができるのであれば、以下のようにして内容を表示することができます。

exec 4<README; while read -u 4; do echo $REPLY; done

4 というのはファイルディスクリプタ番号で、 0 〜 1023 の間の未使用の数値を指定してください。

ちなみに、 TOMOYO Linux ではプログラムの実行時には読み込み権限のチェックはしません。これは、読み込み権限のチェックを行うようにすると、上記の方法によりプログラムの内容を読み出すことができるようになってしまい、スクリプトファイルの中に機密情報を埋め込めなくなってしまうためです。

posted by 熊猫さくら at 20:18| Comment(0) | TrackBack(1) | Linux

2007年02月22日

VMware で複数のゲストを順番に実行する方法について

VMware でいろんなディストリビューションのカーネルをコンパイルしていますが、一度に全てのゲストを並列実行させられるだけのCPUもメモリも無いので、1個ずつ順番に行っています。しかし、コンパイルが終わったゲストをシャットダウンして次のゲストを起動するために人手が必要になってしまっては夜間バッチができません。

幸い、 VMware には -x と -q という起動オプションが存在しているため、以下の条件を満たせば自動的に切り替えできます。

条件は、以下の2点です。
(1)ゲストの起動時に「ハードウェアが見つからない」などのダイアログが表示されないようになっていること。
(2)ゲストが poweroff コマンドによって電源断できること。

準備としては、ゲストを起動して、バッチコマンド(例えば rpmbuild や make-kpkg )を開始した直後にサスペンドさせます。バッチコマンドが始まった瞬間に応答が遅くなってしまうのを避けるために、バッチコマンドの開始前に sleep 10 とかを入れておくとサスペンド操作がスムーズに行くかもしれません。また、バッチコマンドの終了後に poweroff が実行されるようにしておきます。これをゲストの数だけ繰り返します。

準備ができたら、全ての VMware を閉じます。

その後、仮想マシンを順番に実行させるスクリプトを作成します。

Linux の場合はこんな感じです。(runvmware.sh)

#! /bin/sh
for i in "$@"
do
  vmware -x -q $i
done

chmod 755 runvmware.sh; ./runvmware.sh /var/vmware/*/*.vmx みたいに使います。

Windows の場合はこんな感じです。(runvmware.bat)

@ECHO OFF
FOR /F "usebackq tokens=2 delims==-" %%I IN (`FTYPE VMware.Document`) DO SET VMware=%%I
:START
IF "%1"=="" GOTO END
START "" /WAIT %VMware% -x -q %1
SHIFT
GOTO START
:END

コンテキストメニューの「送る」に登録するか、 runvmware.bat の上に *.vmx をドラッグ&ドロップして使います。

VMware Player の場合は -x と -q は不要ですので、 VMware Player しかインストールされていない環境ならば START "" /WAIT %1 のように省略できます。
VMware Player では右上のXボタンを押して閉じると自動的にサスペンドしてくれるので便利ですねぇ。

posted by 熊猫さくら at 05:47| Comment(0) | TrackBack(0) | Linux

2006年10月28日

余談:カーネルソースのパーミッション

http://www.atmarkit.co.jp/flinux/rensai/watch2006/watch10a.html によると David Wagner さんがカーネルのソースのパーミッションが 0666 なのは良くないのではないかと指摘したそうです。

実は、熊猫も http://lkml.org/lkml/2005/12/2/34 で質問したことがあります。

まぁ、 root で作業すべきではないのでしょうけど、 lxr をしようとしたらパーミッションの設定がおかしくて一般ユーザでは読めないファイルがあったという経験もあります。

なので、 TOMOYO Linux のカーネル構築手順書では、 root ユーザのまま tar で展開した直後に
find -print0 | xargs -0 chmod go-w --
するようにしています。

posted by 熊猫さくら at 12:12| Comment(0) | TrackBack(0) | Linux

2006年10月10日

個別環境に認証情報を残さないための Squid の設定について

インターネットへのアクセスにユーザ認証が必要なプロキシを必ず経由しなければいけない環境において、 http_proxy などの環境変数にユーザ認証のための情報を含めたくない場合への対処法です。
注意:私は Squid には詳しくないので、鵜呑みにするのではなく、他のサイトの情報も確認してください。

通常は http_proxy などの環境変数に認証情報と一緒にプロキシサーバを指定しますが、そのようにするとヒストリ機能や設定ファイルや /proc/PID/environ 等から認証情報が丸見えになりやすい状況になってしまいます。そこで、認証情報を環境変数に指定するのではなく、認証情報を追加して上流プロキシサーバへ転送してくれるプロキシサーバを用意して、環境変数にはそのプロキシサーバの情報だけを指定します。

まず、他人がHDD上のファイルを参照してしまう心配の無い環境(例えば Windows XP )に Squid をインストールします。そして、 squid.conf の

# TAG: cache_peer

というセクションの末尾に、以下のように cache_peer を指定します。

cache_peer 上流プロキシのIP parent 上流プロキシのポート番号 3130 no-query no-netdb-exchange login=上流プロキシの認証で使うユーザ名:上流プロキシの認証で使うパスワード

こうしておけば、 squid.conf にアクセスされるかパケットを盗聴されない限り、認証情報が他人に見られないようにできます。

次に、アクセス許可の指定ですが、例えば以下のように指定します。

# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
acl host1 arp アクセスを許可するホスト1のMACアドレス(例:00:0C:29:12:34:56)
acl host1 arp アクセスを許可するホスト2のMACアドレス
acl host1 arp アクセスを許可するホスト3のMACアドレス
acl local-servers dst 上流プロキシを経由しないネットワーク(例:192.168.0.0)/ネットマスク(例:255.255.255.0)
always_direct allow local-servers
never_direct allow all
http_access allow host1

誰でも自分のユーザ名とパスワードで上流プロキシにアクセスされては困るので、MACアドレスで制限を掛けます。なお、MACアドレスによる制限は同一ネットワークセグメント上でないと使えません。

「GET はできるのに POST ができない」場合は never_direct allow all を忘れているものと思われます。 POST の場合はデフォルトでは上流プロキシを経由しないで直接目的のサーバにアクセスしようとしてしまうようです。しかし、上流プロキシを経由しないとアクセスできない環境の場合は never_direct を指定する必要があります。

また、目的のサーバがローカルアドレスの場合、上流プロキシを経由しないで直接目的のサーバにアクセスしなければいけない場合もあります。そのような場合は、 acl dst で上流プロキシを経由しないサーバを定義し、 never_direct allow all よりも前に always_direct allow を指定する必要があります。

posted by 熊猫さくら at 20:27| Comment(0) | TrackBack(0) | Linux

2006年09月26日

FC6 でカーネル rpm を作成する際の注意点

Fedora Core 6 で kernel-2.6.18-1.2693.fc6.src.rpm から rpmbuild でバイナリパッケージを作ろうとした時に起こりそうなトラブルへの対処法です。

通常は、

rpmbuild -bb --target i586 /usr/src/redhat/SPECS/kernel-2.6.spec

と実行するだけでカーネル rpm を作成することができます。
しかし、 http://kumaneko-sakura.sblo.jp/article/696897.html で述べたように、デフォルトの .config ファイルでは CONFIG_DEBUG_INFO というオプションが有効になっているため、大量のディスク領域(約 2.5 GB?)が必要となります。

そこで、 /usr/src/redhat/SPECS/kernel-2.6.spec を開き、以下のように CONFIG_DEBUG_INFO= で始まる行を # CONFIG_DEBUG_INFO is not set に変更してやるための行を挿入することで、ディスク領域を節約することができます。

# now run oldconfig over all the config files
for i in *.config
do
  mv $i .config
  Arch=`head -1 .config | cut -b 3-`
  sed -i "s/CONFIG_DEBUG_INFO=.*/# CONFIG_DEBUG_INFO is not set/" .config
  make ARCH=$Arch nonint_oldconfig > /dev/null
  echo "# $Arch" > configs/$i
  cat .config >> configs/$i
done

しかし、 Fedora Core 6 ではこれだけではエラーになってしまいます。
FC6 では、以下のように %define _enable_debug_packages 0 という行も追加してやる必要があるようです。

%ifarch %nobuildarches
%define buildup 0
%define buildsmp 0
%define buildpae 0
%define buildxen 0
%define buildkdump 0
%define _enable_debug_packages 0
%endif

%define _enable_debug_packages 0

#
# Three sets of minimum package version requirements in the form of Conflicts:
# to versions below the minimum
#
posted by 熊猫さくら at 21:36| Comment(0) | TrackBack(0) | Linux

2006年09月18日

接続元ポート制限によるSSHサーバの保護について

別にSSHに限った話ではないのですが、多くのサーバはクライアントの使用するポート番号をチェックしません。
クライアントは未使用の非特権ポート(1024以上のポート)を見つけだしてそのポートを使用してサーバに接続するためです。
そのため、クライアントが使用するポート番号を制限することで、サーバが受け付けるべきポート番号を制限することも可能になり、ある程度サーバを攻撃対象になりにくくすることができます。

具体的には、クライアント側で

wget -O proxy.c http://lists.sourceforge.jp/mailman/archives/tomoyo-users/attachments/20060918/2b39ee3a/proxy.obj
gcc -Wall -O3 -o path_to_output proxy.c

でコンパイルします。 path_to_output は実行可能ファイルの出力先です。

次に、

ProxyCommand path_to_output %h %p min_port max_port

という内容のコンフィグファイルを作成し、適当な名前をつけて(例: useproxy )保存します。
min_port と max_port はそれぞれサーバが受け付けるクライアントの最小のポート番号と最大のポート番号です。

接続するときには、

ssh -F useproxy remote_host

のように -F オプションを指定してコンフィグファイルを指定します。
remote_host は接続先のサーバです。

デフォルトでこの設定を使いたい場合は ~/.ssh/config または /etc/ssh/ssh_config に記述しておきます。

min_port=1 max_port=10 としてクライアント側を設定した場合、サーバ側では

iptables -I INPUT 1 -p tcp --dport 22 --sport 11:65535 -j DROP

のようにファイアウォールを設定してサーバが受け付けるべきポート番号を制限することができます。
何も知らない攻撃者が 1024 以降のポート番号を利用して接続を試みても、ポートスキャンの時点で門前払いされるようになるわけです。

認証失敗ログと iptables を連動させて接続元 IP アドレスによる制限を行うSSHブルートフォース対策は有名ですが、 ちょっと工夫すれば、接続元ポート番号による対策も可能になります。

SSH クライアントが接続時に使用するローカルポートの範囲を制限する機能を備えていれば簡単なんだけどなぁ・・・。

posted by 熊猫さくら at 12:12| Comment(0) | TrackBack(0) | Linux

2006年09月16日

起動時に少しでも早くコンソールログインする方法について

通常、システム起動時には /etc/rc.d/rc による処理が完了してからコンソールログイン用のプロンプトが表示されます。
デフォルトの /etc/inittab の内容は以下のような内容になっているでしょう。

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

(中略)

# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

しかし、ネットワークケーブルが繋がっていなかったり設定が不適切だったことが原因で、 /etc/rc.d/rc が数分間停止してしまう場合があります。
sshd が起動後であれば ssh でログインしてレスキューすることができますが、それ以前の段階で停止してしまうことが多く、不便です。
そこで、以下のように tty2 〜 tty6 用の /sbin/mingetty の行を /etc/rc.d/rc より前に移動させます。

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit

2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

(中略)

# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1

こうしておくと、 /etc/rc.d/rc.sysinit が終了して /etc/rc.d/rc が開始された時点からコンソールログインできるようになり、レスキュー時に威力を発揮するでしょう。
ログインするウィンドウの切り替えは Alt + F2 〜 Alt + F6 でできます。

posted by 熊猫さくら at 10:07| Comment(1) | TrackBack(0) | Linux

2006年09月13日

仮想ディスクファイルの圧縮時に圧縮率を高めるためのお掃除について

http://kumaneko-sakura.sblo.jp/article/475732.html の続きです。
ちゃんとしたプログラムにしてみたのでソースを載せておきます。

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    int fd;
    static char buffer[4096];
    memset(buffer, 0, sizeof(buffer));
    snprintf(buffer, sizeof(buffer) - 1, "%s/XXXXXX", argc > 1 ? argv[1] : "");
    if ((fd = mkstemp(buffer)) != EOF) {
        unlink(buffer);
        memset(buffer, 255, sizeof(buffer));
        while (write(fd, buffer, sizeof(buffer)) > 0);
        sync();
        close(fd);
    }
    return 0;
}

このソースを wiper.c という名前で保存し、 gcc -Wall -O3 -o wiper wiper.c のようにコンパイルします。その後、ランレベル1に移行して ./wiper を実行するとお掃除できます。
/ 以外にもハードディスク用のパーティションがマウントされている場合には、コマンドラインオプションでマウントポイントを指定して実行ください。例えば / と /boot 用のパーティションがある場合は ./wiper / と ./wiper /boot のように2回実行してください。

posted by 熊猫さくら at 21:58| Comment(0) | TrackBack(0) | Linux

2006年08月15日

OpenSUSE で Yast が動作しなくなるエラーについて

無事にソフトウェアのアップデートができるようになったと思ったら、今度は Yast が動作しないというトラブルに遭遇しました。 GUI 版ではアイコンをクリックしても新しいウィンドウが開かず、 CUI 版も以下のようなエラーメッセージが表示されます。

tomoyo:/root # yast
warning: the ncurses frontend is installed but does not work
You need to install yast2-ncurses to use the YaST2 text mode interface

いろいろ試した結果、 libzypp を再インストールする(強制的に古いバージョンに戻す)ことで動作するようになりました。

rpm -e --nodeps libzypp
rpm -ivh /media/SU1010_001/suse/i586/libzypp-0.0.8-154.i586.rpm

libzypp ってバージョンアップしてはいけないのかなぁ?まさかね?(^x^;

posted by 熊猫さくら at 20:03| Comment(0) | TrackBack(0) | Linux

OpenSUSE でソフトウェアアップデートを有効にするためのプロキシの設定について

Yast の設定でプロキシの設定をすることができますが、不思議なことに環境変数にはプロキシ認証部分が反映されないようです。
私の環境では http_proxy 環境変数の値は「http://プロキシ認証で使用するユーザ名:プロキシ認証で使用するパスワード@プロキシサーバのアドレス:プロキシサーバのポート」という形式で設定されていなければいけないのですが、何故か環境変数は「http://プロキシサーバのアドレス:プロキシサーバのポート」となってしまいます。

手動で環境変数を設定し直してアップデートの有無のチェックをしていたのですが、いつまで経っても1個もアップデートが無いという状態が続き、不思議に思っていました。いろいろ探してみた結果、ソフトウェアのアップデートを行うためには別途 rug コマンドを使ってプロキシの設定をする必要があるようです。

以下のように設定してください。

rug set proxy-url http://プロキシサーバのアドレス:プロキシサーバのポート
rug set proxy-username プロキシ認証で使用するユーザ名
rug set proxy-password プロキシ認証で使用するパスワード

rug get で現在の設定値を表示することができます。

しかし、いざダウンロードする段階で、ダウンロードをするプログラムが rug で設定した値ではなく http_proxy 環境変数を参照してしまったため、うまくダウンロードできませんでした。結局、 squid を用意して cache_peer 項目に「login=プロキシ認証で使用するユーザ名:プロキシ認証で使用するパスワード」というオプションを指定することで上位プロキシへリクエストを転送するときに挿入してもらうことにしました。(笑)

posted by 熊猫さくら at 20:00| Comment(0) | TrackBack(0) | Linux

2006年07月11日

SuSE カーネルのコンパイル方法について

openSuSE 10.1 のカーネルをコンパイルする際にはいくつか注意点があります。
ここで説明しているのは TOMOYO Linux カーネルをコンパイルする際に試行錯誤して見つけた手順です。正式なコンパイル手順については私は知りません。(^^;

カーネルをコンパイルしてインストールする場合は以下のようにします。
まず、カーネルソースの rpm をインストールします。

rpm -ivh kernel-source-2.6.16.13-4.i586.rpm

これにより、 /usr/src/linux-2.6.16.13-4 へのシンボリックリンクである /usr/src/linux と /usr/src/linux-2.6.16.13-4-obj へのシンボリックリンクである /usr/src/linux-obj が作成されます。
あとは、 kernel-default の場合、 /usr/src/linux-obj/i386/default/ ディレクトリへ移動して通常通りコンパイルします。

cd /usr/src/linux-obj/i386/default/
make -s menuconfig
make -s
make -s modules modules_install install

しかし、カーネルのバイナリ rpm を作成する場合は上記手順とは異なります。
まず、カーネルソースのソース rpm をインストールします。

rpm -ivh kernel-source-2.6.16.13-4.src.rpm

これにより、 /usr/src/packages/SOURCES/ ディレクトリにいくつかの .spec ファイルが作成されます。
そして、 kernel-default の場合、以下のようにコンパイルします。他のディストリビューションのように /usr/src/packages/SPECS/kernel*.spec を使うのではないことに注意してください。

rpmbuild -bb /usr/src/packages/SOURCES/kernel-default.spec

ディスク領域とコンパイル時間を節約するために私は kernel-default.spec を以下のように修正して使っています。

----- Start of patch -----
diff -u kernel-default.spec.org kernel-default.spec
--- kernel-default.spec.org 2006-05-03 18:31:20.000000000 +0900
+++ kernel-default.spec   2006-07-13 22:35:32.000000000 +0900
@@ -123,7 +123,7 @@
 # Will modules not listed in supported.conf abort the kernel build (0/1)?
 %define supported_modules_check 0
 # Are we building with debug symbols enabled?
-%define with_debug %(set -- " %optflags "; [ "$1" = "${1/ -g }" ]; echo $? )
+%define with_debug 0
 %define tolerate_unknown_new_config_options 0
 # kABI change tolerance (default in maintenance should be 4, 8 or 15;
 # see scripts/kabi-checks)
----- End of patch -----

また、 /usr/lib/rpm/find-requires.ksyms の実行中に "/usr/lib/rpm/find-requires.ksyms: line 12: /usr/bin/nm: Argument list too long" というエラーが出ると思われます。このエラーは以下のように修正することで回避できます。

----- Start of patch -----
# diff -u find-requires.ksyms.org find-requires.ksyms
--- find-requires.ksyms.org     2006-04-23 09:28:28.000000000 +0900
+++ find-requires.ksyms 2006-06-12 19:05:19.000000000 +0900
@@ -9,7 +9,7 @@
 esac

 all_provides() {
-    nm "$@" \
+    for module in "$@"; do nm -- $module; done \
     | sed -r -ne 's:^0*([0-9a-f]+) A __crc_(.+):\1\t\2:p' \
     | sort -k2 -u
 }
----- End of patch -----

ちなみに、 rpm パッケージを作成するために以下のようにするのはNGです。

rpm -ivh kernel-source-2.6.16.18-3.i586.rpm
cd /usr/src/linux/
cp -a /usr/src/linux-obj/i386/default/.* .
make -s rpm-pkg

この場合、以下のようなエラーメッセージが表示されます。

Finding Supplements: /usr/lib/rpm/find-supplements kernel
error: line 48: Dependency tokens must begin with alpha-numeric, '_' or '/':

error: Failed to find Supplements:

また、作成されたパッケージも rpm -ivh でインストールしようとすると "ksym(...) = ... is needed by kernel-..." というエラーが表示され、 --nodeps オプションを追加しないとインストールできないものになります。ただし、この問題は CONFIG_MODVERSIONS を使わない設定(# CONFIG_MODVERSIONS is not set)にすれば回避できるようです。

posted by 熊猫さくら at 20:14| Comment(0) | TrackBack(0) | Linux

2006年06月13日

http_proxy にパスワードを指定する場合の注意点(続)

http://kumaneko-sakura.sblo.jp/article/517004.html で DNS パケットによるパスワード誤流出の可能性について示しましたが、実際に環境を作って試してみました。

/etc/resolv.conf に自分自身を指定します。

[root@tomoyo ~]# cat /etc/resolv.conf
nameserver 127.0.0.1

即席のパケットダンプを行うプログラムを用意します。

[root@tomoyo ~]# cat dnsdump.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
  struct sockaddr_in addr;
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(53);
  if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
    int i, len;
    int size = sizeof(addr);
    static char buf[65536];
    while ((len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &size)) != EOF) {
      for (i = 0; i < len; i++) {
        if (buf[i] >= 32 && buf[i] <= 126) putchar(buf[i]);
        else putchar('=');
      }
      putchar('\n');
    }
  }
  return 0;
}

コンパイルして実行します。

[root@tomoyo ~]# gcc -Wall -O3 dnsdump.c
[root@tomoyo ~]# ./a.out

別の画面で、以下のコマンドを実行します。

[root@tomoyo ~]# export http_proxy="http://USER:@PASS@WORD@127.0.0.1:8080"
[root@tomoyo ~]# wget http://localhost/
--16:33:02--  http://localhost/
           => `index.html'
Resolving pass@word@127.0.0.1... failed: Host not found.
[root@tomoyo ~]# yum update
Gathering header information file(s) from server(s)
Server: Red Hat Linux 9 (i386)
retrygrab() failed for:
  http://riksun.riken.go.jp/pub/Linux/fedoralegacy/redhat/9/os/i386/headers/header.info
  Executing failover method
retrygrab() failed for:
  http://download.fedoralegacy.org/redhat/9/os/i386/headers/header.info
  Executing failover method
failover: out of servers to try
Error getting file http://riksun.riken.go.jp/pub/Linux/fedoralegacy/redhat/9/os/i386/headers/header.info
[Errno 7] HTTP Error (CannotSendRequest):

./a.out を実行中の画面には、以下のような内容が表示されるはずです。

=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=u===========PASS@WORD@127=0=0=1=====
=u===========PASS@WORD@127=0=0=1=====
=v===========PASS@WORD@127=0=0=1=====
=v===========PASS@WORD@127=0=0=1=====
=w===========PASS@WORD@127=0=0=1=====
=w===========PASS@WORD@127=0=0=1=====
=x===========PASS@WORD@127=0=0=1=====
=x===========PASS@WORD@127=0=0=1=====

ちゃんとパスワードが流出していることを確認できました。

この原因は、 http_proxy の内容を最初に出現した @ の位置で分割してしまうためです。 @ が複数回出現したらエラーにしてくれると嬉しいんですがね。しかし、 RFC1738 によると、ユーザ名やパスワードの部分に @ を使ってはいけないということになっているので、アプリケーションの責任ではなく、ユーザの責任ということになるのでしょう。

話は違いますが、ユーザ名やパスワードをホスト名のように見せかけるといった攻撃手法もあるんですね。 http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20040306/141018/ 「URL ユーザ名 偽装」で検索するといろいろ出てきました。

posted by 熊猫さくら at 20:15| Comment(0) | TrackBack(0) | Linux

2006年05月18日

カーネルモジュールを小さくするためのコツについて

カーネル 2.6 には、 CONFIG_DEBUG_INFO という名前のコンパイルオプションが存在します。このオプションが有効である場合、コンパイルされたコードのサイズが約8倍〜10倍の大きさになります。
このオプションが有効になっている場合、(カーネルのコンフィグにもよりますが) /usr/src/ ディレクトリで約1GB、 /lib/modules/ ディレクトリで約300MBの余分なディスク領域を消費します。いくつかのディストリビューションではデフォルトで有効になっています。
ディスク領域を節約したい場合、以下のオプションが選択されていないことを確認してください。

Kernel hacking --->[ ]  Compile the kernel with debug info

VMware のようにディスク領域が貴重な場合は無効にすることを推奨します。私の場合、このオプションに気がつくまでは仮想ディスクを10GB割り当てていましたが、このオプションを無効にすることで4GBでやりくりできるようになりました。

posted by 熊猫さくら at 21:22| Comment(0) | TrackBack(0) | Linux

2006年03月31日

http_proxy にパスワードを指定する場合の注意点

認証が必要なプロキシ環境( http_proxy や ftp_proxy で「 http://プロキシユーザID:プロキシパスワード@プロキシホスト:プロキシポート」のような指定を行っている環境)で使用する場合には、以下の点に注意してください。

1つ目は、コマンドラインヒストリが有効になっているシェルから入力しないことです。私は、ヒストリが有効になっている bash から入力せずに、ヒストリが無効になっている tcsh を起動してから入力するようにしています。尤も、他のプロセスの環境変数(/proc/<PID>/environ)へのアクセスが可能であればどのみち盗まれてしまうわけですが。

2つ目は、パスワードに @ を使ってはいけないということです。これは、 http_proxy に @ が含まれている場合、最初の @ 以前を「プロキシユーザID:プロキシパスワード」、最初の @ 以降を「プロキシホスト:プロキシポート」として解釈するため、 「プロキシパスワード」に @ が含まれていると、「 @ 以降の部分」がプロキシホストのホスト名だと解釈されて、DNSの問い合わせパケット経由でプロキシサーバ以外のサーバにプロキシパスワードの一部を教えてしまうことになります。
これに気が付くまでは、どうしてホスト名が解決できないのか悩みました。そして、 http_proxy にパスワードを指定できるようにするために、わざわざパスワードを変更しました。もしも、「プロキシユーザID」に @ が含まれていたら「プロキシパスワード」全体をDNSサーバに教えてしまうことになるのでしょうね。怖くて試していませんけど。

posted by 熊猫さくら at 20:09| Comment(0) | TrackBack(0) | Linux

2006年03月23日

yum の罠

yum はコマンド1つでパッケージを最新版にアップデートしてくれる便利なプログラムですが、気をつけなければいけない点が2つあります。

1つは、設定ファイルに最新版を置いてあるサーバを指定しておくことです。全てのサーバが永遠に最新版を置き続けてくれる訳ではないため、時々確認してやらないと、最新版が存在しているのに当該サーバに置かれてないからダウンロードされないという状況が発生します。

もう1つは、キャッシュされたメタデータを時々削除することです。「yum update」を実行しても何もダウンロードされず、「最近、パッケージの更新が全然無いようだけどどうしたのかな?」と思ったら、「yum clean metadata」または「yum clean all」を実行してみてください。
その後、再度「yum update」を実行すると・・・「あら不思議。 yum clean metadata を実行前に yum update したときには表示されなかったパッケージが次々とダウンロードされてきた。」なんてことがあります。何かの拍子に、 yum が管理するメタデータが最新の情報を反映しなくなってしまうようです。

posted by 熊猫さくら at 21:49| Comment(0) | TrackBack(1) | Linux

2006年03月20日

簡単に作れる find もどき

Linux には ftw という関数があります。これは、 find コマンドのように指定されたディレクトリ以下をスキャンする関数です。以下、 RedHat Linux 9 で find もどきの関数を作る方法を紹介します。

プログラムの先頭で、ファイルサイズを64ビットで扱えるように以下の3行を記述します。これを指定しないと、32ビットでは扱えないファイルに遭遇した場合に ftw がエラーになってしまいます。

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE

次に、以下の内容を記述します。(これらの内容は、 #include <ftw.h> で取り込まれるはずなのですが、何故かうまくいかないので直接記述します。)

#include <sys/types.h>
#include <sys/stat.h>
#define FTW_PHYS 1
struct FTW;
int nftw64(const char *dir, int (*fn)(const char *file, const struct stat64 *sb, int flag, struct FTW *s), int nopenfd, int flags);

コールバック関数 fn は、以下のような内容です。

#include <stdio.h>
int ftw_func(const char *file, const struct stat64 *sb, int flag, struct FTW *s) {
    printf("%s\n", file); // ここに処理内容を記述します。
    return 0;
}

呼び出し方は以下のようにします。

if (nftw64("/", ftw_func, 1000, FTW_PHYS)) {
    fprintf(stderr, "nftw64() returned %d\n", errno);
    exit(1);
}

これだけで、 find / 相当の機能が実現できます。詳細は man ftw を参照してください。

posted by 熊猫さくら at 22:04| Comment(0) | TrackBack(0) | Linux

2006年03月17日

仮想ディスクファイルの圧縮時に圧縮率を高めるためのファイルの削除方法について

VMware 仮想マシンを持ち運ぶために zip ファイル化したり、ホスト側のディスク領域を節約するために NTFS 等の圧縮機能を利用したりすることがあると思います。

通常のファイル圧縮の場合、必要なファイルだけを圧縮することができるため、圧縮されたファイルのサイズを小さくすることができます。
しかし、仮想ディスクファイルを圧縮する場合、その中に含まれる全てのデータを圧縮する必要があります。仮想ディスクファイル内の消去されたデータまで圧縮を行うことになり、消去されたデータの内容によっては全く圧縮が効きません。

しかし、逆に言えば、消去されたデータの内容を圧縮が効きやすいものに書き換えてやれば、消去されたデータが最初から存在しなかった場合と同じくらいの圧縮効果を期待できます。

以下は、約3GBの ISO イメージファイルを VMware 環境内からダウンロードして、ホスト側に移動後、そのファイルを削除した後のディスクの使用量です。 NTFS の圧縮機能で圧縮していますが、あまり小さくなっていません。

before-zeroclear.png

以下は、そのディスクの空き領域を全てゼロクリア(実際にはスパースファイル化されると困るので 0xFF でクリア)してみた結果です。

after-zeroclear.png

最初からディスク領域を割り当てずに必要に応じて拡大していく方式を利用しているので、未使用の領域までゼロクリアしたことで圧縮前のディスク使用量も若干増えてしまっていますが、圧縮後のディスク使用量は ISO イメージファイルのサイズと同じくらい減少していることがわかります。 (ファイルの内容が含まれている領域だけゼロクリアできれば、未使用の領域までゼロクリアしないで済むので、圧縮前のディスク使用量の増加も避けられます。)

/bin/rm や /bin/unlink にファイルの内容をゼロクリアしてから削除するようなオプションがあると嬉しいですね。

posted by 熊猫さくら at 19:56| Comment(0) | TrackBack(0) | Linux

2006年03月13日

お遊び:テンポラリファイルで使われるパス名を見つけようとしたら・・・

テンポラリファイルを作成する場合、パス名の末尾を XXXXXX としてテンポラリファイルを作成する関数を呼び出すようになっています。そのため、 XXXXXX で終わる文字列は、テンポラリファイルとして使われるパス名である可能性が高いわけです。そこで、 strings を使ってそのような文字列の抽出を試みたのですが、予想外の結果が出てきました。

find / -type f -perm +100 -print0 | xargs -0 strings -f -- | grep -F XXXXXX

を実行すると、インストールされているパッケージによっては面白いものが表示されます。

strings に渡す -f オプションは、ファイル名を表示するためのものです。最初は -f を指定せずに実行したため、一瞬「ウィルスに感染したのか?」と疑ってしまいました。(笑)

大量にヒットするので、スクロール機能が無いコンソールから実行すると一瞬で消えてしまいます。スクロールバッファを1000行以上に設定してお試しください。

ちなみに、ウィルスに感染したのかと疑ってしまうような表示をしていたのは、 /usr/bin/xboard でした。

posted by 熊猫さくら at 20:08| Comment(0) | TrackBack(0) | Linux

2006年03月11日

scp の罠

ssh を使ってコピーを行う scp には、ちょっと困った問題点があるようです。

問題1

例えば、

scp -p 'remotehost: ; touch /tmp/testfile' .

と実行すると、 remotehost で touch /tmp/testfile というコマンドを実行できてしまいます。

これは、接続元の scp が remotehost のログインシェルを「-c 'scp -p -f "接続元で実行された scp に渡された引数から最初の : までを取り除いたもの"'」という形式で起動するため、 remotehost のログインシェルは「scp -p -f "接続元で実行された scp に渡された引数から最初の : までを取り除いたもの"」つまり「scp -p -f ; touch /tmp/testfile」というコマンドを展開して実行してしまうためです。

もしも、

scp -p 'root@remotehost: ; rm -fR /*' .

などというパラメータを渡された場合には、全ファイルが削除されてしまうことでしょう。

このように ; を使って余計なコマンドを実行されないようにするには、 rssh を使う必要があります。

問題2

しかし、 rssh を使っても、 remotehost で scp の実行を禁止できるわけではない点に注意が必要です。 scp は remotehost 上でも scp を起動することで動作するように設計されているためです。

scp は、 -f オプションが指定されておらず、ファイル名に : が含まれている場合には、そのファイルがリモートホスト上にあると判断して ssh を起動してしまいます。つまり、 remotehost1 で rssh が使われていても、

ssh remotehost1 'scp -p remotehost2:/etc/passwd .'

というコマンドを実行することは可能なわけです。そのため、自動的に remotehost1 から remotehost2 へ接続できるような設定になっている(例えば remotehost2 の ~/.ssh/authorized_keys に remotehost1 の公開鍵が登録されている)場合、

ssh remotehost1 'scp -p -i ~/.ssh/id_rsa remotehost2:/etc/passwd .'
scp -p remotehost1:passwd .

とすることで、 remotehost1 にログインできる任意のホストから remotehost2 の /etc/passwd が取得できてしまいます。

問題3

また、ファイル名に : が含まれている場合、ホスト名を指定する区切り文字だと解釈されてしまい誤動作の原因になります。例えば、

touch /tmp/file1 /tmp/somehost:file2
cd /tmp/
scp -p file1 somehost:file2 remotehost:/tmp/

と実行しても、 /tmp/somehost:file2 を remotehost にコピーすることができません。 ただし、ファイル名に : が含まれる場合でも、 : より前に / が出現すれば問題ないようですので、

touch /tmp/file1 /tmp/somehost:file2
cd /tmp/
scp -p file1 ./somehost:file2 remotehost:/tmp/

のようにすれば回避できます。

問題4

また、

scp -p -f file1 remotehost:/tmp/

のように、 -f オプションが指定されてしまうと入力待ち状態になってしまいます。もしも、

touch /tmp/-f
cd /tmp/
scp -p * remotehost:/tmp/

と実行した場合、 * の展開結果として -f が先頭に来てしまい、

scp -p -f * remotehost:/tmp/

と同様の結果になりかねません。これを回避するには、

touch /tmp/-f
cd /tmp/
scp -p ./* remotehost:/tmp/

のように ./ を指定するのが良いと思います。もし、

scp -p -- * remotehost:/tmp/

のように -- を指定しても、 * を展開した結果 somehost:file2 のようなファイルが含まれてしまう可能性があり、問題3が発生してしまいます。

posted by 熊猫さくら at 15:13| Comment(2) | TrackBack(0) | Linux

2006年02月13日

メモ: apt-get による emacs のインストール

Debian Sarge で emacs をインストールしようとしてはまりました。

「apt-get install emacs」と指定してもインストールできないので不思議に思っていたら、 「apt-get install emacs21」と指定すれば良いことが判りました。(笑)

posted by 熊猫さくら at 20:44| Comment(0) | TrackBack(0) | Linux