5    監査レコードの生成

この章では,次の内容について説明しています。

5.1    監査レコードの概要

トラステッド・プログラムは,以下の理由から独自の監査レコードを生成することがあります。

トラステッド・プログラムは,audgen() システム・コール,audgenl() ライブラリ・ルーチン,または audgen コマンドを使って監査レコードを生成できます。audgenl() は,audgen() のフロント・エンドです。このプログラムは引数として,監査イベントと,その後に監査データ (監査トークンと値からなる) を渡します。

次のコードでは,ブート認証をチェックするプログラムから audgenl() を呼び出して認証の失敗を監査する方法を示しています。

if(audgenl(AUTH_EVENT,  [1]
           AUD_T_LOGIN, pr->ufld.fd_name,  [2]
           AUD_T_UID, pr->ufld.fd_uid,
           AUD_T_CHARP, "boot authentication failed"),0)== -1)
perror("audgenl");
 
 

注:

  1. AUTH_EVENT は,レコードのイベント名です。 [例に戻る]

  2. AUD_T_LOGINAUD_T_UID,および AUD_T_CHARP は,トークンです。それぞれ,対応する値を持っています。 [例に戻る]

これらの識別子は,<sys/audit.h> に定義されています。イベントとトークンの説明は,5.2 節および 5.3 節を参照してください。

5.2    監査イベント

各監査レコードには,それに対応する監査イベントがあります。システムは,システム・コールの監査レコードを生成するときに,自動的にイベントを追加します。自己監査アプリケーション・プログラムは,監査レコードを生成するときに,イベントを audgen() または audgenl() に引数として渡します。アプリケーション・プログラムで利用できる監査イベントには,2 つのタイプがあります。

5.3    監査レコードとトークン

監査サブシステムでは,固定レコード・タイプは使用しません。監査レコードは,タプル (2 つ以上の構成要素があるデータ・オブジェクト) が連続しています。各タプルは,監査トークンとそれに対応するで構成されます。トークンのタイプによっては,タプルに長さフィールドが存在することもあります。

以降の項では,2 つのタイプのトークン (パブリック・トークンプライベート・トークン) について説明しています。アプリケーション・プログラムでは,パブリック・トークンを使います。

5.3.1    パブリック・トークン

audgen() および audgenl() を使って監査レコードを生成するアプリケーション・プログラムでは,パブリック・トークンを利用できます。パブリック・トークンは,<sys/audit.h> に定義されており,AUD_T_ で始まります。たとえば,AUD_T_CHARP です。

パブリック・トークンには 3 つの基本タイプがあります。

ポインタ

ポインタとしてデータ文字列または構造体を表現するために使います。AUD_T_CHARP (文字列) と AUD_T_HOMEDIR (ホーム・ディレクトリ) はどちらも,ポインタ・タイプのトークンです。

iovec

データを iovec フォーマットのデータとして表現するために使います。AUD_T_OPAQUEAUD_T_INTARRAY はどちらも,iovec タイプのトークンです。<sys/audit.h> 内の iovec のコメントを参照してください。iovec 構造体は,<sys/uio.h> に定義されています。iovec についての詳細は, readv(2) および writev(2) のリファレンス・ページを参照してください。

固定長

データを 32 ビットまたは 64 ビットの量として表現するために使います (AUD_T_RESULT と AUD_TP_LONG は,64 ビットです。その他は,32 ビットです)。ほとんどのトークンでは,固定長データを使います。AUD_T_AUID (監査 ID),AUD_T_UID (ユーザ ID),および AUD_T_PID (プロセス ID) は,固定長トークンの例です。

次の例では,iovec フォーマットのデータを使って監査レコードを生成します。

#define AUD_COMPAT
#include <sys/audit.h>
#include <sys/uio.h>
 
main()
{
     char buf[100];
int i;
     struct iovec iov;
 
     for (i = 0; i < sizeof(buf); i++)
          buf[i] = i;
 
     iov.iov_len = sizeof(buf);
     iov.iov_base = buf;
 
     if (audgenl (AUDGEN8,
                  AUD_T_CHARP, "opaque data test",
                  AUD_T_OPAQUE, &iov,
                  0 ) ==  -1 )
         perror ("audgenl");
}

5.3.2    プライベート・トークン

プライベート・トークンは,カーネルが使います。アプリケーション・プログラムでは,このトークンは使用できません。audgen() システム・コールは,プライベート・トークンを持つレコードにアプリケーション・プログラムが書き込もうとすると拒否します。プライベート・トークンは,<sys/audit.h> に定義されており,AUD_TP_ で始まります。たとえば,AUD_TP_AUID です。

カーネルは,監査レコードを作成するときにプライベート・トークンを使います。たとえばカーネルは,各監査レコードを AUD_TP_LENGTH タプル (値がその監査レコードの長さを示す) でカプセル化します。別の例としては,audgen() または audgenl() の引数 event があります。カーネルはこの引数から,AUD_TP_EVENT タプルを作成します。

5.4    監査フラグとマスク

監査イベントによって実際に監査レコードが生成されるかどうかは,次のフラグとマスクの設定で決まります。

プロセス監査制御フラグには,4 つの排他的な状態があります。

AUDIT_OR

システム監査マスクとプロセス監査マスクのいずれかで監査が必要と示されたイベントの場合,監査レコードが生成されます。

AUDIT_AND

システム監査マスクとプロセス監査マスクの両方で監査が必要と示されたイベントの場合,監査レコードが生成されます。

AUDIT_OFF

現プロセスに対して監査レコードは生成されません。

AUDIT_USR

プロセス監査マスクで監査が必要と示されたイベントの場合,監査レコードが生成されます。

また,プロセス監査制御フラグには,排他的でない状態が 2 つあります。

AUDIT_SYSCALL_OFF

プロセスに対するシステム・コールのレコード生成をオフにします。

AUDIT_HABITAT_USR

システム・マスクでシステム・コールがオフになっていても,プロセスのユーザ・マスク内のハビタット・システム・コールをオンにします。ハビタット・システム・コールには,System V - unlink()open(),real time - memlk()memunlk()psx4_time_drift()rt_setprio() があります。これらのハビタット・システム・コールは,グループとしてオン,オフされます。ハビタット・イベントについては,付録 Bを参照してください。

システム管理者は,管理者が適切と判断するレベルで個々のユーザを監査する機能を残したまま,ユーザに対して省略時の監査レベルを指定することができます (監査サブシステムの構成と管理については『セキュリティ管理ガイド』を参照してください)。

プログラマから見ると,特権プロセスがその監査レベル (監査対象の指定) を設定できます。この監査レベルは,絶対マスクとして設定するか,システム監査マスクとの関連で設定します。プロセスの監査マスクの設定方法を示す例は,5.6 節 を参照してください。詳細については, audcntl(2) および auditmask(8) を参照してください。

5.5    現プロセスのシステム・コール監査の無効化

どのイベントを監査するかを制御することは,監査データ収集の量を適切にチューニングするための重要なステップです。システム・コールは,大量の監査データを生成する可能性があります。しかし,このデータは,必ずしも役立つ情報とは限りません。一般的に,セキュリティ関連のデータベース内のフィールドの変更を積極的に監査したり,特定のセキュリティ関連アクションを監査すると,多数のシステム・コール監査レコードから得られる情報よりも,役立つ情報を入手できます。たとえば,ログイン・プロセスはたくさんのシステム・コールを実行しますが,ログイン・プロセスが情報として書き込む 1 つの監査レコードの方が,使用するシステム・リソースが少なく,簡単に理解することができます。

アプリケーション・プログラムは,トラステッド・イベントの監査を許可したまま,システム・コール監査を無効にすることができます。次のコードでは,audcntl() システム・コールを使って AUDIT_SYSCALL_OFF を設定する方法を示しています。

    /* OR the AUDIT_SYSCALL_OFF bit into the audcntl flag */
    if ((cntlflag = audcntl(GET_PROC_ACNTL,
                            NULL, 0, 0, 0, 0)) == -1)
        perror("audcntl");
    else
        audcntl(SET_PROC_ACNTL, NULL, 0,
                cntlflag|AUDIT_SYSCALL_OFF, 0, 0);

5.6    現プロセスのシステム・コールの監査の変更

プロセスは,ターゲット・プロセスの auditmask フラグと audcntl フラグを変更することによって,プロセス自身または別のプロセスに対して何を監査するかを制御できます。次のように,現プロセスの監査マスクを変更できます。

    /* ex. set the process's auditmask to audit only LOGIN
       events and successful setgroups calls
    */
    #include <sys/audit.h>
    #include <sys/syscall.h>
    char buf[AUDIT_MASK_LEN];
    
.
.
.
bzero (buf, sizeof(buf)); A_PROCMASK_SET (buf, LOGIN, 1, 1); A_PROCMASK_SET (buf, SYS_setgroups, 1, 0); if (audcntl (SET_PROC_AMASK, buf, AUDIT_MASK_LEN, 0, 0, 0) == -1) perror ("audcntl");

<sys/audit.h> に定義されている A_PROCMASK_SET マクロは,次の引数を取ります。

buf

マスクが設定されているバッファです。

event name

ヘッダ・ファイル <sys/audit.h> には,トラステッド・イベント名があります。ヘッダ・ファイル <sys/*syscall.h> には,システム・コール名があります。

succeed

成功を監査するかどうかを示します。1 は,イベントの成功を監査することを意味します。

fail

失敗を監査するかどうかを示します。1 は,イベントの失敗を監査することを意味します。

詳細については, audcntl(2) を参照してください。

5.7    アプリケーション固有の監査レコード

アプリケーション・プログラムは,アプリケーション固有の監査データを audgen() または audgenl() への引数として渡します。

次のコードは,指定された event が発生したときに,監査レコードをカーネルに送信します。event は,<sys/audit.h> からのトラステッド・イベントか,/etc/sec/site_events からのサイト定義イベントです。(カーネルが監査レコードを監査ログに実際に書き込むかどうかは,このプロセスで監査されているイベントによります)。

/* If bad_thing occurs, generate an event of type event_num,
 * with string "bad thing happened", and a result of 66.
 */
 
#include <sys/audit.h>
 
if (bad_thing) {
   if (audgenl (event_num,
                AUD_T_CHARP, "bad thing happened",
                AUD_T_RESULT, 66, 0 ) == -1)
      perror ("audgenl");
}

通常,アプリケーションが生成する監査レコードには,表 5-1 に示すトークンのデータを入れる必要はありません。カーネルは,この情報を各監査レコードに自動的に追加します。ただし監査サブシステムは,監査レコードにパブリック・トークンのタプルが追加されるのを妨げません。たとえば,システムが後から AUD_TP_AUID を監査レコードに追加する場合でも,AUD_T_AUID タプルを監査レコードに追加できます。このような場合は両方のタプルが監査ログに書き込まれます。

5.8    サイト定義イベント

サイトでは,独自の監査イベントの設定 (サイト定義イベント) を,ローカルに作成され保守されるファイル /etc/sec/site_events で定義できます。このファイル内には,各サイト・イベントに対するエントリが 1 つあります。

使用可能なサイト・イベント番号は,MIN_SITE_EVENT (<sys/audit.h> に定義されている) 〜 1048576 です。省略時の範囲は,64 です。この値を変更するには,/etc/sysconfigtab 内の audit-site-events を設定してから,リブートします。たとえば,サイト定義イベントを最大 128 個にするには,次のように設定します。

 
     sec:
         audit-site-events=128

各サイト・イベント・エントリは,INT_MAX 個までのサブイベントを持つことができます。サブイベントには,省略時の範囲は定義されていません。

イベントまたはサブイベントの名前の最大長は,<sys/audit.h> に定義されている AUD_MAXEVENT_LEN です。

アプリケーション・プログラムは,サイト定義イベントと,<sys/audit.h> に定義されているトラステッド・イベント (MIN_TRUSTED_EVENTMAX_TRUSTED_EVENT) の両方を持つレコードを生成できます。

auditmask ユーティリティは,サイト定義イベントの事前選択をサポートしています。また,audit_tool ユーティリティは,サイト定義イベントとサブイベントの事後選択をサポートしています。

5.8.1    サンプルの site_events ファイル

サイト定義監査イベント・エントリの構文は次のとおりです。

[イベント名 イベント番号 [ , サブイベント名 サブイベント番号 ... ] ;]

サンプルの /etc/sec/site_events ファイルの次のエントリは,サイト定義イベントおよびサブイベントの作成方法を示しています。

essence 2048,     [1]
    ess_read 0,   [2]
    ess_write 1;  [3]
rdb 2049,
    rdb_open 0,
    rdb_close 1,
    rdb_read 2,
    rdb_write 3;
decinspect 2050;

注:

  1. essence はイベントです。2048 はイベント番号です。2048 は MIN_SITE_EVENT で,サイト定義イベントに使用できる最小値です。 [例に戻る]

  2. ess_read は 1 番目のサブイベントです。0 は 1 番目のサブイベント番号です。 [例に戻る]

  3. ess_write は 2 番目のサブイベントです。1 は 2 番目のサブイベント番号です。 [例に戻る]

サイト定義イベントについての詳細は, aud_sitevent(3) を参照してください。

5.8.2    例: サイト定義監査イベントの監査レコードの生成

次のコードは,audgenl() を使って,rdb_close イベントの監査データを生成します。

int event_num, subevent_num;
 
/* translate event name(s) into event numbers */
if (aud_sitevent_num ("rdb", "rdb_close",
                      &event_num, &subevent_num ))
    printf ("aud_sitevent_num failed");
 
/* generate audit data */
else if (audgenl (event_num,
                  AUD_T_SUBEVENT, subevent_num,
                  AUD_T_CHARP, "Trusted RDB V1.0 Close",
                  0) == -1)
    perror ("audgenl");

サイト定義イベントのレコードを生成する場合は,audgenl()AUD_T_CHARP, event name という引数を含めてください。これにより,ローカルの site_events ファイルのコピーを持たないシステムで監査データを解析する作業が簡単になります。

詳細については, aud_sitevent(3) および audgenl(3) を参照してください。

5.9    独自の監査ログの作成

audgen() システム・コールを使って,独自の監査ログを作成できます。audgen() への引数 size がゼロ以外の値の場合,監査データは,システム監査ログに書き込まれるのではなく,audgen() で指定した userbuff へコピーされます。この後,トラステッド・アプリケーションは,userbuff のデータを固有のログ・ファイルに書き込むことができます。詳細については, audgen(2) を参照してください。

audit_tool ユーティリティを使って,新しい監査ログを読み取ることができます。5.10 節の説明を参考に,ログから詳しい情報を読み取ることができます。

5.10    監査ログの解析

多くの人が,audit_tool または dxaudit を使用して監査ログを参照します。audit_tool ユーティリティは洗練されたプログラムで,監査データを役立つ情報に変換したり,出力をフォーマットしたり,複数の監査ログ・ファイルにまたがる監査レコードを処理します。audit_tool は,監査ログを最初に読み取ったとき,そのログに対応する .hdr ファイルを作成して,状態情報を保守します。この状態情報により,その後の監査ログの読み取りに必要な時間が短縮されます。また,監査レコードが複数のログにまたがる場合は,audit_tool が両方のログ・ファイルをオープンし,ヘッダ・ファイル内に完全なレコードを作成します。

以降の項では,監査ログのフォーマットと構造について,次のような情報を説明しています。

以降の項では,audit_tool のようなプログラムを作成するために必要な,設計に関する情報は説明していません。監査ログを解析してレコードとタプルに分解するために必要な基本情報について説明しています。

5.10.1    監査ログのフォーマットの概要と共通タプルのリスト

監査ログは,通常の UNIX データ・ファイルで,監査レコードが格納されています。監査レコードは,フォーマットが token:value または token:length:value のどちらかの,連続したタプルで構成されています。各レコードは,AUD_TP_LENGTH タプルで始まり,AUD_TP_LENGTH タプルで終わります。audit_tool ユーティリティは,監査レコードが有効かどうかを判断するのに AUD_TP_LENGTH を使います。レコードの実際の長さが AUD_TP_LENGTH の値と一致しない場合は,audit_tool がレコードを破棄し,警告を出力します。表 5-1 は,監査レコードで広く使われている省略時のタプルを示しています。

表 5-1:  大半の監査レコードに共通する省略時のタプル

タプル コメント タプル コメント
AUD_TP_LENGTH   AUD_TP_VERSION  
AUD_TP_AUID   AUD_TP_RUID  
AUD_TP_HOSTADDR   AUD_TP_EVENTP ハビタットの場合
AUD_TP_HABITAT ハビタットの場合 AUD_TP_EVENT  
AUD_TP_UID   AUD_TP_PID  
AUD_TP_PPID   AUD_TP_DEV デバイスがプロセスに対応している場合
AUD_TP_NCPU   AUD_TP_TV_USEC  
AUD_TP_SET_UIDS uid の変更の場合 AUD_TP_TID AUDIT_USR フラグが設定されている場合

5.10.2    トークンおよびタプルのバイト記述

表 5-2 は,パブリック・トークンとプライベート・トークンを,8 進値と一緒に示しています。各タプルの 3 番目の欄は,カーネルが監査ログに書き込むタプル・データのシーケンスを示しています。トークンは 1 バイト,長さは 4 バイトです。サンプルの解析マクロは,audit_tool がタプルを解析するために使うマクロを示しています。参考として,これらのマクロを5.10.3 項に記載します。

表 5-2:  トークンおよびタプルのバイト記述

トークン 8 進値 タプルのフォーマットとサンプルの解析マクロ
AUD_T_CHARP 001 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_SOCK 003 トークン:長さ:struct sockaddr (4.3 スタイル (u_short)。family > UCHAR_MAX の場合は 4.4 スタイルの sockaddr となり,「長さ」(バイト) の後に family (バイト) が続く)。PARSE_DEF3
AUD_T_LOGIN 004 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_HOMEDIR 005 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_SHELL 006 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_DEVNAME 007 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_SERVICE 010 トークン:長さ:ヌル終了する ASCII 文字列。(将来の使用のために予約済み)
AUD_T_HOSTNAME 011 トークン:長さ:ヌル終了する ASCII 文字列。PARSE_DEF3
AUD_T_INTP 012 トークン:長さ:int (1 番目の要素は配列内の要素の数。監査レコードの生成時には,AUD_T_INTARRAY の方が適切なタプルである。PARSE_DEF3
AUD_T_LSOCK 016  
AUD_T_RSOCK 017  
AUD_T_LHOSTNAME 020  
AUD_T_OPAQUE 030 トークン:長さ:値 (proplist または本当の opaque。proplist の名前と値の組をチェックし,なければ 16 進でダンプ)。PARSE_DEF6
AUD_T_INTARRAY 031 トークン:長さ:int。PARSE_DEF3
AUD_T_GIDSET 032 トークン:長さ:int1, int2, ... (境界合わせなし)。PARSE_DEF3
AUD_T_XDATA 033 トークン:struct aud_xdata (<sys/audit.h> を参照)。PARSE_DEF8
AUD_T_AUID 040 トークン:int。PARSE_DEF2
AUD_T_RUID 041 トークン:int。PARSE_DEF2
AUD_T_UID 042 トークン:int。PARSE_DEF2
AUD_T_PID 043 トークン:int。PARSE_DEF2
AUD_T_PPID 044 トークン:int。PARSE_DEF2
AUD_T_GID 045 トークン:unsigned int。PARSE_DEF2
AUD_T_EVENT 046 トークン:int。PARSE_DEF2
AUD_T_SUBEVENT 047 トークン:int。PARSE_DEF2
AUD_T_DEV 050 トークン:int (<sys/types.h> のマクロ major() および minor() を使って解析する)。PARSE_DEF2
AUD_T_ERRNO 051 トークン:int。PARSE_DEF1
AUD_T_RESULT 052 トークン:long。PARSE_DEF4
AUD_T_MODE 053 トークン:unsigned int。PARSE_DEF2
AUD_T_HOSTADDR 054 トークン:unsigned int。PARSE_DEF2
AUD_T_INT 055 トークン:int。PARSE_DEF2
AUD_T_DESCRIP 056 トークン:int (ファイル記述子)。PARSE_DEF2
AUD_T_HOSTID 057 トークン:int。PARSE_DEF1
AUD_T_X_ATOM 060 トークン:unsigned int。PARSE_DEF2
AUD_T_X_CLIENT 061 トークン:int。PARSE_DEF2
AUD_T_X_PROPERTY 062 トークン:int。PARSE_DEF2
AUD_T_X_RES_CLASS 063 トークン:unsigned int。PARSE_DEF2
AUD_T_X_RES_TYPE 064 トークン:unsigned int。PARSE_DEF2
AUD_T_X_RES_ID 065 トークン:unsigned int。PARSE_DEF2
AUD_T_LHOSTNAME 066  
AUD_T_SECEVENT 177 トークン:int。PARSE_DEF2
AUD_TP_ACCRGHT 201 トークン:長さ:cmsg_data (fd1, fd2, ... 。<sys/socket.h> を参照)。PARSE_DEF3
AUD_TP_MSGHDR 202 トークン:長さ:msghdr->msg_name (<sys/socket.h> を参照)。PARSE_DEF3
AUD_TP_EVENTP 203 トークン:長さ:string。PARSE_DEF3
AUD_TP_HABITAT 204 トークン:長さ:string。PARSE_DEF3
AUD_TP_ADDRVEC 205 トークン:長さ:struct sockaddr (socket.h を参照)。PARSE_DEF3
AUD_TP_INTP 206 トークン:長さ:int。PARSE_DEF3
AUD_TP_AUID 241 トークン:int。PARSE_DEF1
AUD_TP_RUID 0242 トークン:int。PARSE_DEF1
AUD_TP_UID 0243 トークン:int。PARSE_DEF1
AUD_TP_PID 0244 トークン:int。PARSE_DEF1
AUD_TP_PPID 0245 トークン:int。PARSE_DEF1
AUD_TP_HOSTADDR 246 トークン:unsigned int。PARSE_DEF1
AUD_TP_EVENT 247 トークン:int。PARSE_DEF1
AUD_TP_SUBEVENT 250 トークン:int (将来の使用のために予約済み)。PARSE_DEF1
AUD_TP_NCPU 251 トークン:int。PARSE_DEF1
AUD_TP_DEV 252 トークン:int (sys/types.h のマクロ major() および minor() を使って解析する)。PARSE_DEF1
AUD_TP_LENGTH 253 トークン:int。PARSE_DEF1
AUD_TP_IPC_GID 254 トークン:unsigned int (ipc|msg|shm_perm.gid)。PARSE_DEF2
AUD_TP_IPC_MODE 255 トークン:unsigned int (ipc|msg|shm_perm.mode)。PARSE_DEF2
AUD_TP_IPC_UID 256 トークン:int (ipc|msg|shm_perm.uid)。PARSE_DEF2
AUD_TP_TV_SEC 257 トークン:timeval.tv_sec (<sys/time.h> を参照)。PARSE_DEF1
AUD_TP_TV_USEC 260 トークン:timeval.tv_usec (<sys/time.h> を参照)。PARSE_DEF1
AUD_TP_SHORT 261 トークン:short。PARSE_DEF2
AUD_TP_LONG 262 トークン:long。PARSE_DEF5
AUD_TP_VNODE_DEV 263 トークン:int。PARSE_DEF2
AUD_TP_VNODE_ID 264 トークン:unsigned int。PARSE_DEF2
AUD_TP_VNODE_MODE 265 トークン:unsigned int。PARSE_DEF2
AUD_TP_VERSION 266 トークン:unsigned int。(<sys/audit.h> を参照)。(AUD_VERSION | AUD_VERS_LONG) PARSE_DEF1
AUD_TP_SET_UIDS 267 トークン:int。PARSE_DEF2
AUD_TP_CONT 270 トークン:unsigned int (レコードの各構成要素に固有の int)。PARSE_DEF1
AUD_TP_TID 271 トークン:long。PARSE_DEF4
AUD_TP_PRIV 272 トークン:unsigned short。PARSE_DEF1

5.10.3    タプルの解析

監査レコードのストリームを読み取るアルゴリズムは次のとおりです。

  1. 監査ログをオープンします。

  2. 最初の監査レコードを見つけます (AUD_TP_LENGTH タプルで始まり,AUD_TP_LENGTH タプルで終わります)。

  3. レコード長が AUD_TP_LENGTH タプルの値と一致するかチェックします (長さが一致しない場合は,レコードを破棄します)。

  4. AUD_TP_LENGTH タプルに続く最初のタプルを取り出します。

  5. タプルが可変長の場合は,データのサイズを調べます。

  6. データを抽出します。

  7. 次のタプルを取り出し,必要に応じて長さをチェックします。そして,データを抽出します。

  8. レコードがなくなるまで繰り返します。

  9. 監査ログをクローズします。

次のマクロは,audit_tool がどのようにタプルを解析するかを示しています。これらのマクロは,参考として記載しているだけで,1 つの手段を示しているに過ぎません。indx の値は,audit_tool が保守し,使用します。この値は,監査レコードのタプルの一部ではありません。

/* fixed length scalar value */
#define PARSE_DEF1(tokentype,field) \
  bcopy (&rec_ptr[i+sizeof token], &field, sizeof(field)); \
  i += (sizeof token + sizeof(field)); \
break;
 
/* fixed length field in array */
#define PARSE_DEF2(tokentype,field,indx) \
  if (indx < AUD_NPARAM) \
      bcopy (&rec_ptr[i+sizeof token], &field[indx++], sizeof(field[0])); \
  i += (sizeof token + sizeof(field[0])); \
break;
 
/* array of strings */
#define PARSE_DEF3(tokentype,len,field,indx) \
  bcopy (&rec_ptr[i+sizeof token], &j, sizeof(int)); \
  if (j >= rec_len) j = 0; \
  if (indx < AUD_NPARAM) { \
      len[indx] = j; \
      field[indx++] = (char *)&rec_ptr[i+(sizeof token)+(sizeof *intp)]; \
  } \
  i += (sizeof token + sizeof *intp + j); \
break;
 
/* fixed length scalar value whose size is h/w dependent (32 or 64-bit) */
#define PARSE_DEF4(tokentype,field) \
  bzero (field.val, sizeof(field.val)); \
  j = af->version & AUD_VERS_LONG ? sizeof(int)*2 : sizeof(int); \
  bcopy (&rec_ptr[i+sizeof token], field.val, j); \
  i += (sizeof token + j); \
break;
 
/* fixed length field in array whose size is h/w dependent (32 or 64-bit) */
#define PARSE_DEF5(tokentype,field,indx) \
  bzero (field[indx].val, sizeof(field[indx].val)); \
  j = af->version & AUD_VERS_LONG ? sizeof(int)*2 : sizeof(int); \
  if (indx < AUD_NPARAM) \
      bcopy (&rec_ptr[i+sizeof token], field[indx++].val, j); \
  i += (sizeof token + j); \
break;
 
/* array of opaque data streams */
#define PARSE_DEF6 PARSE_DEF3
 
/* iovec element in array */
#define PARSE_DEF7(tokentype,field,indx) \
  j = sizeof(field[0]); \
  if (indx < AUD_NPARAM) { \
      bcopy (&rec_ptr[i+sizeof token], &j, sizeof(int)); \
      if (j > rec_len ) j = 0; \
      bcopy (&rec_ptr[i+sizeof token+sizeof(int)], &field[indx++], j); \
  } \
  i += (sizeof token + sizeof(int) + j); \
break;
 
/* array of iovec elements with variable length components */
#define PARSE_DEF8(tokentype,field,ptr,indx) \
  j = sizeof(field[0]); \
  if (indx < AUD_NPARAM) { \
      bcopy (&rec_ptr[i+sizeof token], &j, sizeof(int)); \
      if (j > rec_len) j = 0; \
      bcopy (&rec_ptr[i+sizeof token+sizeof(int)], &field[indx], j); \
      ptr[indx++] = ((struct aud_xdata *) \
                    &rec_ptr[i+sizeof token+sizeof(int)])->xdata; \
  } \
  i += (sizeof token + sizeof(int) + j); \
break;