ApachephpからSambaユーザーを追加したかったのにハマったのでメモ

Sambaユーザーの追加はsmbpasswdコマンドで行えるが、
ワンライナーなコマンドがなく、対話式でパスワードを入力する事でしか作成ができない。
またsmbpasswdはrootユーザーでなければ実行できないので
Apachephpから実行する場合はパーミッションエラーとなる。

[code]

smbpasswd -a hogehoge

New SMB password:
Retype new SMB password:
Added user hogehoge.
[/code]

sudoを導入

まずはApacheユーザーがroot権限でsmbpasswdコマンドを実行できるようにsudoを導入する。
[code]
apt-get install sudo
[/code]
今回、Apachedaemonというユーザーで動かしていたのでdaemonがsudoコマンドでroot権限で操作できるよう設定する
[code]
visudo
以下の一文を追加
daemon ALL=(ALL) NOPASSWD: ALL
[/code]
※今回は完全にローカルなサーバーなのでこのように設定していますがセキュリティ的には非常にまずいので特定のスクリプトのみにsudo権限を与える等、慎重に行って下さい。

上記作業でdaemonユーザーはコマンド前にsudoを付ける事でroot権限で実行する事が可能になりました。

expectの導入

上記の作業でApachephpから「sudo smbpasswd -a hogehoge」といったコマンドをexecするだけでroot権限で実行が可能となりました。
しかしsmbpasswdは対話式のコマンドである為、普通に実行すれば
「New SMB password:」と聞かれて止まってしまいます。

そこで対話式をサポートするexpectというプログラムを導入します。
[code]
apt-get install expect
[/code]

expectはシェルスクリプトから呼び出し可能なので以下のようなシェルスクリプトを作成し、ワンライナーsambaユーザーが作成できるようにします。

[code]
vi smbpasswd.sh
[/code]
以下のように作成
[code]

!/bin/bash

usage | ./smbpasswd.sh username passwd

if [ $# -ne 2 ]; then
echo “error”
exit 1
fi

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
interact

[/code]
実行権限を与える
[code]
chmod 755 smbpasswd.sh
[/code]

これで以下のように実行すればsambaユーザーが作成できるようになりました。
以下の例ではhogehogeユーザーがパスワード123123として作成されます。
[code]

./smbpasswd.sh hogehoge 123123

New SMB password:
Retype new SMB password:
Added user hogehoge.
[/code]

Apachephpから実行するとうまくいかない

上記のシェルスクリプトApachephpから実行してみます。

test.php
[code]
<?php
exec("sudo ./smbpasswd.sh hogehoge 123123",$str);
foreach($str as $v){
echo $v . "<br />”;
}
?>
[/code]

ブラウザから接続してみるも、どうもexpectがうまくいっていないようで
「Retype new SMB password:」部分で止まっている事がわかりました。

以下のようにすると解決

シェル上からの実行だとうまくいくのにApachephpから実行するとうまくいかない、、、
すごく頭を悩ませましたが、expectの文を以下のように編集するとうまくいくようになりました。

[code]
vi smbpasswd.sh
[/code]
以下のように作成
[code]

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
interact

↓以下のように編集

expect smbpasswd

expect -c ”
set timeout 10
spawn smbpasswd -a $1
expect \”New SMB password:\”
send \”$2\n\”
expect \”Retype new SMB password:\”
send \”$2\n\”
expect \”x\”
send \”\n\”
interact

[/code]

追加したのは
expect \”x\”
send \”\n\”
という文章で、どうやらApacheから実行した場合は上記のように適当なexpect文を入れておかなければ最後の行で止まってしまうようでした。
この原因は未だによくわかってないですが、上記のようにする事で動かす事ができるようになりました。