💦

Laravel Windows Serverでschtasksのアクセスが拒否されました問題

2021/08/25に公開

こちらのLaravelでシェルコマンドを実行する記事と関わります。

schtasks失敗の問題

Process Componentを使って、シェルコマンドを実行するコードをコントローラに書きましたが、本番機でテストしてみるところで、なんとschtasksとのコマンドが失敗します。

環境はWindows Server, Laravel 6, SQL Server, Apache。コマンドの内容というのは、他のリモートサーバのタスクを実行するものとなります。大まかなコードは以下となります。

$response = ['status' => 0, 'msg' => ''];
$task_code = $request->query('task');
// ...
//'C:\Windows\System32\schtasks.exe /run /s \\\\xx.xxx.xxx.xx /u xxxx /p xxxx /tn';
$cmd = config('const.CMD');
// ['code_1' => 'task_a', 'code_2' => 'task_b', ]
$task = config('const.TASKS')[$task_code];

try {
    $process = Process::fromShellCommandline("{$cmd} \"{$task}\"");
    $process->run();
    $output = $process->getOutput() ?: $process->getErrorOutput();

    if ($process->isSuccessful()) {
        $response['status'] = 1;
        $response['msg'] = 'タスクが成功しました。';
    } else {
        $response['msg'] = 'タスク' . $task . 'が失敗しました。';
        throw new ProcessFailedException($process);
    }
} catch (\Exception $e) {
     Log::error(__FILE__ . " (" . __LINE__ . ")" . PHP_EOL . $e->getMessage());
}   

これでやってみると、以下のエラーでタスクが失敗します。ただ、直接コマンドラインから実行すると成功します。ちなみに、exec関数に変えても同じくエラーで失敗します。

エラー:アクセスが拒否されました

誰がコマンドを実行しているか

関連情報を色々と検索してみると、管理者権限での実行が必要、という若干曖昧な情報がありました。確実かどうかはわかりませんが、様々なコマンドを試してみて、結論として少なくともschtasksに関しては権限絡みの問題の可能性が高いと。

ここでよく分からないのは、Laravelの中でコマンドを実行するときに、「誰が実行しているのか」というところです。ログイン中のユーザーは既に管理者なので、もしログイン中のユーザーが実行しているのであれば、失敗しないはずです(直接コマンドラインからの実行は成功しているので)。

それで管理者権限でコマンドを実行する方法を検索して、runasいうコマンドを勧める内容がありました。

exec("echo {$pw} | runas /user:administrator \"{$cmd}\"", $output, $code);

上記のコマンドでechoのstdoutをrunasのstdinとしてパイプしようとしていますが、残念ながら不可能の様子です。参考記事は[こちら](Why doesn't the RunAs program accept a password on the command line? | The Old New Thing)。どうやらセキュリティー事情で、runasは必ず手動でパスワードを入力しなければなりません。つまりこのコマンドを実行するとパスワード入力が要求され、$cmdのコマンドは絶対実行されません(検証済み)。

runasの代替コマンドとして、psexecというコマンドのがあるらしいです。

psexec [\\computer[,computer2[,...] | @file]][-u user [-p psswd][-n s][-r servicename][-h][-l][-s|-e][-x][-i [session]][-c executable [-f|-v]][-w directory][-d][-<priority>][-a n,n,...] cmd [arguments]

ただこちらは別途ツールをインストールしないといけないので、色々と大人の事情で面倒なことになります。なのでこちらの方法は一旦保留としました。

と結構悩んでいたところ、検索キーワードを少し変えて、'php exec access denied'とかで検索し、こちらの内容を見つけました。直接schtasksと関わっていないですが、なんとなくこれっぽい気がしました。下記の手順通り、ApacheサービスのユーザーをSYSTEMから管理者に変更したら、エラーがなくなりました。

  • サービスを開く
  • Apache2.4を右クリック、プロパティを選ぶ
  • ログオンタブで、ローカルシステムアカウントから、アカウントに切り替える
  • アカウント情報を現在ログイン中の管理者ユーザーに設定
  • Apacheサービスを再起動

Laravelの中でコマンドを実行するときに、「誰が実行しているのか」という問題の答えになるかもしれませんが、今までの状況で推測すると、デフォルトのSYSTEMユーザー(Local System Account)となっていて、SYSTEMには、なんらかの理由で権限が足りないため、「アクセスが拒否されました」、となってのではないかと。

誰かの役に立つかどうか分かりませんが、わけわからんトラップにハマって、何とか抗えて脱出した経験として記録しておきます。

以上です!

GitHubで編集を提案

Discussion