Windows7でのアクセストークンの変更エラー


take  2015-08-11 20:10:29  No: 47532

Delphi2007でシャットダウンや日付変更を行うためアクセス権を変更して実行しています。

WindowsXPまでは正常に動作していたのですが
Windows7(64bit)で試すと
「一部の特権が呼び出し側に割り当てられていません」
というエラーが帰ってきます。もちろんアクセス権は変更出来ません。

デバッグ環境を使わず、実行ファイルから「管理者権限で実行」をすると
エラーは無く正常に動作するのですが、これは理想ではありません

この辺のサイトを見て試行錯誤しているのですが
どれも同じエラーが出ます。
アクセス権の設定に問題があるのでしょうか?

http://ht-deko.com/tech043.html
http://homepage1.nifty.com/project21/articles/delphi/tips07.htm
http://www.geocities.jp/asumaroyuumaro/program/tips/setlocaltime.html

procedure ProcessTokenOpen(const ProcessName : PChar);
var
  hToken    :THandle;  //アクセストークンのハンドル
  tkp, origintkp :TTokenPrivileges;
  ReturnLen :DWord;
begin
  //WinNT の場合SE_SYSTEMTIME_NAME特権の有効化が必要
  if Win32Platform = VER_PLATFORM_WIN32_NT then
  begin
    //プロセスのアクセストークンを開く
    if OpenProcessToken(GetCurrentProcess,
                        TOKEN_ADJUST_PRIVILEGES or
                        TOKEN_QUERY, hToken) then
    begin
      try
        //特権名を示す一意のLuidを取得
        if not LookupPrivilegeValue(nil, ProcessName,
                                    tkp.Privileges[0].luid) then Exit;
        //構造体の中の特権数
        tkp.PrivilegeCount := 1;
        //SE_SYSTEMTIME_NAME 特権を有効にする
        tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        //新しいアクセストークン情報(tkp)を適用する
        //origintkpには適用以前の情報が返される
        if not AdjustTokenPrivileges(hToken, False, tkp,
                                      Sizeof(origintkp), origintkp, ReturnLen) then
          Exit;
        if (GetLastError <> ERROR_SUCCESS) then
        begin
          raise Exception.Create(SysErrorMessage(GetLastError));
          Exit;
        end;
      finally
        //アクセストークンを閉じる
        CloseHandle(hToken);
      end;
    end;
  end;
end;


tor  2015-08-11 22:46:56  No: 47533

ヲサヲサエラーが帰ってきます
と言いますが、エラーを返したのはどの関数ですか?
と聞こうとしてコードを見たら、ヌフナの使い方がおかしいような……何だかデジャヴ……

ヌフナは
ィアゥヲサ関数の呼び出し結果を確認して、結果が「失敗」だった時に
ィイゥヲサじゃあ、失敗した理由は何?ヲサと調べるために呼び出す
ものです。ィアゥの前提なしにィイゥだけやったら、無実の人に罪を着せるだけになってしまいます。

今のコードの構造を見ると
  ヲサチの結果ヲサスヲサ失敗ヲサヲサナサ
  ヲサツの結果ヲサスヲサ失敗ヲサヲサナサ
  ……
  ヲサヌフナヲサヲサヲサヲサナメメマメ゜モユテテナモヲサヲサエラーだ!
となってますが、これじゃおかしいですよね?
肝心のエラーのときは何もせずスルーして、誰もエラーを返していない時に「エラーが起きてるぞ!ヲサ誰のせいだ!」と騒ぎ立てているだけです。

やるとしたら
  ヲサチの結果ヲサスヲサ失敗ヲサ
  
    ヌフナで原因を調べて何とかする
    ナサ
  サ
  ヲサツの結果ヲサスヲサ失敗ヲサ
  
    ヌフナで原因を調べて何とかする
    ナサ
  サ
  ……
  ここまで来られたら成功!

のような流れにしなくてはいけませんね。
(実際には同じコードを何度も書かずに済むよう、もう少し構造を工夫するでしょうけど)
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アエコウオコエカ シ  スュアセシ上級者セ シッニセシノヘヌ ス「コッッョョョッッウョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン

ヲサさんレスありがとうございます。

「エラーが出ます」と書きましたが自分でエラー判断していましたね。

チヤミの行で正常終了しません
チヤミは正常時「ー」異常時「ー」以外ですので

ヲサヲサヲサヲサヲサチヤミィヤャヲサニャヲサャ
ヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサモィゥャヲサャヲサメフゥヲサ
ヲサヲサヲサヲサナサ
正常終了時は、これ移行の処理がキャンセルされます。
異常時に処理が継続され
ヌフナヲサの返値調査になります。

ヌフナヲサは正常時「ー」です。
ナメメマメ゜モユテテナモモヲサはヲサ「ー」で定義されていますので

ヲサヲサヲサヲサヲサヲサィヌフナヲサヲサヲサヲサナメメマメ゜モユテテナモモゥヲサ
ヲサヲサヲサヲサヲサ
異常時にヲサが真になって

ヲサヲサヲサナョティモナヘィヌフナゥゥサ

異常内容を表示する。
となっています。

肝心の呼び出し方が抜けていました
【システム時刻の変更権限の取得】
ヲサヲサミヤマィァモモミァゥサ

これをトレースするとエラーとして処理されます

【シャットダウン権限の取得】
ヲサヲサミヤマィァモモミァゥサ

こっちはエラーは出ません

色々調べたのですが
ログイン時には日時の変更権限はありませんでした。
管理者権限に昇格した場合は日時の変更権限がありました。

シャットダウンの権限は  ログイン時にもありました

最初から無い権限は追加出来ないのかな・・・
スススススススススススススススススススススススススススススススススススススススス
ニコ 初心者
トコ イーアオッークッアアィ火ゥ アエコエアコウク シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 」「。   ン

ヲサヲサチヤミの行で正常終了しません
ヲサヲサチヤミは正常時「ー」異常時「ー」以外ですので

上級者になるとヘモトホを見なくてもチミノの戻り値が分かるんですね。さすがです。

ヲサヲサチヤミヲサ関数
ヲサヲサコッッョョッュッッテエーアケウクョ

ヲサヲサ関数が成功すると、ーヲサ以外の値が返ります。
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アエコエアコエケ シ  スュアセシ上級者セ シッニセシノヘヌ ス「コッッョョョッッウョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン

あと記述したソースはリンク先のものですので・・・
とにかくわかりやすく修正しました。

ヲサミヤマィヲサミホヲサコヲサミテゥサ

ヲサヲサヤヲサヲサヲサヲサコヤネサ
ヲサヲサャヲサヲサコヤヤミサ
ヲサヲサメフヲサコトラサ

ヲサヲサヲサヲサラウイミヲサスヲサヨナメ゜ミフチヤニマメペラノホウイ゜ホヤヲサヲササ

ヲサヲサヲサヲサマミヤィヌテミャ
ヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヤマヒナポチトハユモヤ゜ミメノヨノフナヌナモヲサ
ヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヤマヒナポムユナメルャヲサヤゥヲサヲササ
ヲサヲサ
ヲサヲサヲサヲサヲサヲサフミヨィャヲサミホャ
ヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサョミローンョゥヲサヲサナサ

ヲサヲサヲサヲサョミテヲサコスヲサアサ
ヲサヲサヲサヲサョミローンョチヲサコスヲサモナ゜ミメノヨノフナヌナ゜ナホチツフナトサ
ヲサヲサヲサヲサヲサヲサチヤミィヤャヲサニャヲサャ
ヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサヲサモィゥャヲサャヲサメフゥヲサヲササ
ヲサヲサヲサヲサヲサィヌフナヲサスヲサナメメマメ゜モユテテナモモゥヲサヲササ
ヲサヲサヲサヲサヲサナョティモナヘィヌフナゥゥサ

ヲサヲサ
ヲサヲサヲサヲサテネィヤゥサ
ヲサヲササ


スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アエコエオコアオ シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン

ヲサヲサチヤミは正常時「ー」異常時「ー」以外ですので
逆でしたたびたびすみません

MSDNから引用します。

ヲサ関数が成功すると、ーヲサ以外の値が返ります。
ヲサ指定したすべての特権に調整が加えられたかどうかを調べるには、
ヲサヌフナヲサ関数を呼び出すと、次の値のいずれかが返ります。

MSDNのリンクも貼っておきます
コッッョョッュッッテエーアケウクョ
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アオコエイコーイ  書込者ノト:ロ 」 ァ」ハノ

 ン

ヲサヲサヌフナヲサは正常時「ー」です。
なんて保証はないですよ。一般に、ヌフナの値が更新されるのはあくまで「エラーが起きた時」です。

ィアゥヲサ関数の返り値を見て、成功か失敗か確認する
ィイゥヲサアの結果が「失敗」だったら、ヌフナで理由を調べる
のが大前提で、ィアゥをとばして
・ヌフナを見て、その結果で直前の関数が成功か失敗か判断する
のは間違いです。

チヤミの説明を見ると、たしかに少々ややこしいことにはなっていますが
「関数の返り値で成功・失敗を判定する」という原則に変わりはありません。
で、リンクされているヘモトホの説明の「戻り値」以降を読むと、チヤミの返しうる結果にはウ種類あることがわかります。
  ィチアゥヲサ指定されたすべての特権を調整したよ!
  ィチイゥヲサ調整できるものはすべて調整したよ!ヲサいくつか存在しない特権があったけどそれは無視したよゴメンネ!
  ィツゥヲサ失敗しちゃったよ!ヲサ理由はヌフナで調べてね!

関数が真(ー以外)を返した場合はィチアゥかィチイゥのどちらかで、
どちらなのかはヌフナの結果で区別できます(この時だけ、原則から外れたヌフナの使い方をすることになります)。
  ナメメマメ゜モユテテナモモヲサ→ヲサィチアゥ
  ナメメマメ゜ホマヤ゜チフプチモモノヌホナトヲサ→ヲサィチイゥ
ィチイゥになった場合は特権が存在しなかったということなので、そもそもユーザにその権限がないということになります。

関数が偽(ー)を返した場合はィツゥのケースです。この場合はヌフナで原因を調べてエラー処理する必要がありますね。
(元のコードだと、この場合に何もせずナしてしまっていますが)
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アオコエクコアー  書込者ノト:ロ 」 ァ」ハノ

 ン

おっと追記。

ヲサヲサ解説
ヲサヲサチヤミヲサ関数は、アクセストークンに新しい特権を追加することはできません。
(以下略)

というわけで確かに、持っていない権限は追加できませんね。
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アオコオキコオイ シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン


エラー処理の方法ありがとうございます。

時刻修正ですが
アクセサリから開いたコマンドプロンプト上で
ヲサコマンドを使用して時刻を修正しようとしても
「クライアントは要求された特権を保有していません」
と表示されますので

どうあがいても管理者にならない限り時刻は修正できないのですかね?

ラのツールである
「ローカルセキュリティポリシー」にて
システム時刻の変更の許可を有効にして試したりしていますが
そちらも手詰まりです。
スススススススススススススススススススススススススススススススススススススススス
ニコ 通りすがり
トコ イーアオッークッアアィ火ゥ アカコーオコーイ  書込者ノト:ロ 」。 。 ン

ミテのシステムクロックを修正するためにはユチテで管理者権限を得る必要があります。
カスタムマニフェストでナフのを「チ「としてみてはいかがでしょうか。
もちろん起動時にはユチテ昇格ダイアログが表示されます。
スススススススススススススススススススススススススススススススススススススススス
ニコ 通りすがり
トコ イーアオッークッアアィ火ゥ アカコーカコアカ  書込者ノト:ロ 」。 。 ン

あ、忘れてました。サービスとして動作させる、という方法もあります。
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アカコアイコーオ シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン

よいアイデアありがとうございます。
ユチテ昇格ダイアログが出るとそこで止まるので少々問題があります。

サービスとして起動するときはダイアログでませんかね?
ちょっと作ったことが無いのでわかりません。

最悪はユチテを切れば良いのかなとは思いますが
そうで無い方法を模索しています。

ローカルセキュリティポリシーの
システム時刻変更権限に  自分自身を追加して試しているのですが
なぜかそれすら有効になりません。

確認方法はコマンドプロンプトからのヲサコマンドです

ト関係なくなってしまっているかも。
スススススススススススススススススススススススススススススススススススススススス
ニコ 通りすがり
トコ イーアオッークッアアィ火ゥ アカコエウコエエ  書込者ノト:ロ 」。 。 ン

そもそもラウイヤィラヲサヤゥサービスでチトかホヤミで時間を合わせるのがラ的には正しいので、
それ以外の方法で、しかも操作するユーザなしで時刻合わせという時点でだめなのです。
ちなみにサービスはユノを基本的には持ちませんが、代わりにフヲサモとかフヲサモという権限で動きます。

ということで、そもそもやりたいことはなんですか?それはラのお作法的に正しいですか?というところを
もう一度考えてみてはいかがですか。
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアアィ火ゥ アキコーオコイエ シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 」。ァ」。 ン

やりたい事はおっしゃる通り
「ユーザー無しで時刻合わせ」です

ラの標準機能には無い時刻の合わせかたをする必要があり
ラリミ用に作っていたものをラキ用に移植しています。

サービスのやり方で一度挑戦したいと思います。
※それ以前にローカルセキュリティポリシーに使用ユーザーを増やしても変わらないので困ってますが

相当な労力を必要とする方法があるにはあるのですが・・・

「モホヤミサーバーを作成してラの同期先を自分自身に設定する」

ラが同期先として認識してくれれば可能かとは思いますが
労力がすごそうです
スススススススススススススススススススススススススススススススススススススススス
ニコ 通りすがり
トコ イーアオッークッアアィ火ゥ アキコアキコアウ  書込者ノト:ロ 」。 。 ン

ユチテ昇格ダイアログが出るのがまずいということは自動処理なのですよね?であればサービス化でしょう。
あとはログオン時にタスクスケジューラ使ってシステム権限で起動するという方法もありますか。
テトノがこれ使いますね。セキュリティオプションに最上位の特権で実行するというのがあります。
スススススススススススススススススススススススススススススススススススススススス
ニコ 
トコ イーアオッークッアイィ水ゥ アーコウーコオイ シ  スュアセシ初心者セ シッニセシノヘヌ ス「コッッョョョッッアョ「 ス「ー「セ 書込者ノト:ロ 「「 ヲ  ン
モコ 

様々な情報ありがとうございます。

サービス化ほか様々な方法で試したいと思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






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