このアーティクルはDelphi Advent Calendar 2022の22日目の記事です(20日ぶり8回目)。
以前WNetAddConnection2を使って他のPCのネットワーク共有にアクセスする方法について書きましたが、これをサービスから実行するとWNetAddConnection2が時々エラー1312(ERROR_NO_SUCH_LOGON_SESSION)になる、という現象が発生します。調べてみたところ、サービスの場合はSystemではなくNetworkServiceで動作していないとこのような状態になるようです(常にエラーになるわけではなく、成功したりエラーになったりという感じ)。もちろんサービスをNetworkServiceで実行すればネットワークアクセスでエラーになることはないのですが、ローカルコンピュータに対するアクセスがUsersグループ相当に制限されてしまいます(サービスで使用する(Local)System/LocalService/NetworkServiceアカウントについてはWindowsテクニカルドキュメント(旧MSDN)のService User Accounts、LocalService Account、NetworkService Account、LocalSystem Accountや@ITのWindowsのサービスで使用される「System」「Local Service」「Network Service」アカウントとは?:Tech TIPSを参照)。
そこでSystemアカウントで動作するサービスから実行することを前提に、ネットワークリソースにアクセスするときだけNetworkServiceアカウントに偽装するようにしてみます。
まずLogonUserでNetworkServiceとしてログインし、返されたトークンハンドルでImpersonateLoggedOnUserを呼び出すことでユーザを偽装します。
これでこの後WNetAddConnection2で接続を試みるときにSystemアカウントではなくNetworkServiceアカウントであるかのように扱われます。
切断するときはまずWNetCancelConnection2を呼び出した後で、RevertToSelfで偽装を解除し、CloseHandleでトークンハンドルをクローズすることでログオフします。
なおプロセス上で複数のスレッドが動作している場合(特にサービス)など、同一の共有リソース('\\<computername>\<sharename>')に対してWNetAddConnection2をネストして呼び出すとERROR_ALREADY_ASSIGNEDでエラーになります。これを防ぐには同一の共有リソースに対してWNetAddConnection2/WNetCancelConnection2が1回ずつ呼び出されるように、接続している共有リソースをプロセス全体で適切に管理する必要もあります。
2022年12月22日
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿