プライマリ・コンテンツに移動
Oracle® Label Security管理者ガイド
12cリリース1 (12.1)
E56367-02
目次へ移動
目次
索引へ移動
索引

前
次

B Oracle Label Securityの高度なトピック

Oracleには、ラベル間の関係を分析する機能など、Oracle Label Securityの高度な機能が用意されています。

内容は次のとおりです。

ラベル間の関係の分析

ラベル間の関係を分析できます。

内容は次のとおりです。

支配するラベルと支配されるラベルについて

2つのラベル間の関係は、支配という用語で説明できます。

ユーザーがオブジェクトにアクセスできるかどうかは、そのユーザーのラベルがオブジェクトのラベルを支配しているかどうかによって決定されます。ユーザーのラベルがオブジェクトのラベルを支配していない場合、ユーザーはそのオブジェクトへのアクセスを許可されません。

ラベルの支配関係は、そのすべてのコンポーネント、つまり、レベル、区分およびグループについて分析されます。

表B-1 ラベルの比較における支配関係

要因 支配関係の基準

レベル

label1label2を支配するには、label1のレベルがlabel2のレベル以上である必要があります。

区分

label1label2を支配するには、label1の区分がlabel2すべての区分を含んでいる必要があります。

グループ

label1label2を支配するには、label1label2のグループの少なくとも1つを含んでいる必要があります。

あるラベルが別のラベルを支配するのは、そのすべてのコンポーネントが別のラベルのコンポーネントを支配している場合です。たとえば、ラベルHIGHLY_SENSITIVE:FINANCE,OPERATIONSは、ラベルHIGHLY_SENSITIVE:FINANCEを支配します。同様に、ラベルHIGHLY_SENSITIVE::WR_APは、ラベルHIGHLY_SENSITIVE::WR_AP, WR_ARを支配します。

比較できないラベル

支配に関してラベルの比較方法を理解するのは重要なことです。

2つのラベル間の関係は、常に支配という用語で定義できるとはかぎりません。どちらのラベルも他方を支配していない場合、2つのラベルは比較できません

2つのラベル間で区分が異なる場合(HS:AHS:Bなど)、両者は比較できません。同様に、ラベルHS:AおよびS:Bは比較できません。

DBA_SA_LABELSデータ・ディクショナリ・ビューを問い合せて、既存のラベルを確認できます。

支配ファンクションの使用

Oracle Label Securityでは、支配を制御する機能が提供されます。

内容は次のとおりです。

支配ファンクションについて

支配ファンクションを使用すると、問合せで範囲を指定できます。

次のファンクションを使用すると、指定したラベル間の支配関係を指定できます。

表B-2 支配関係を決定するファンクション

ファンクション 説明

OLS_DOMINATES

label1の値によりlabel2の値が支配されるか、等しくなります。

OLS_LABEL_DOMINATES

対応するpolicy_nameのセッション・ラベルの値により、labelの値が支配されるか、等しくなります。

OLS_STRICTLY_DOMINATES

label1の値によりlabel2の値が支配され、両者は等しくありません。

OLS_DOMINATED_BY

label1の値はlabel2の値に支配されます。

OLS_STRICTLY_DOMINATED_BY

label1の値はlabel2の値に支配され、両者は等しくありません。

支配ファンクションには2つのタイプがあることに注意してください。SA_UTLの支配ファンクションはBOOLEAN値を戻しますが、スタンドアロンの支配ファンクションは整数を戻します。

OLS_DOMINATESスタンドアロン・ファンクション

OLS_DOMINATES (OLS_DOM) ファンクションは、label1label2を支配している場合は1 (TRUE)、それ以外の場合は0 (FALSE)を戻します。

構文

OLS_DOMINATES (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN INTEGER; 

パラメータ

表B-3 OLS_DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SELECT OLS_DOMINATES ('1111', '1112') FROM DUAL;

OLS_DOMINATES('1111','1112')
----------------------------
                           0

注意:

古いOLSファンクションであるDOMINATESおよびDOMは、Oracle Database 12cリリース1 (12.1)では非推奨です。

このリリースでは古いファンクションを引き続き使用できますが、かわりにOLS_LABEL_DOMINATESおよびOLS_DOMファンクションを使用することをお薦めします。新しいファンクション名を使用すると、他のデータベース・コンポーネントと名前が競合する可能性が回避されます。

OLS_LABEL_DOMINATESスタンドアロン・ファンクション

スタンドアロンOLS_LABEL_DOMINATESファンクションは、セッション・ラベルの支配を確認します。

指定したpolicy_nameの値のセッション・ラベルにより、labelパラメータで指定されるラベルが支配されるか、等しくなる場合は、1 (TRUE)を戻します。それ以外の場合は、0 (FALSE)を戻します。このファンクションは公開されています。

注意:

この機能は、Oracle Database 12cリリース1 (12.1.0.2)以降で使用可能です。

このファンクションは、Oracle Label Securityポリシーに加えて、Oracle Data RedactionポリシーおよびOracle Database Vaultポリシーと併用できます。

構文

OLS_LABEL_DOMINATES (
  policy_name    IN VARCHAR2,
  label          IN VARCHAR2)
RETURN INTEGER;

パラメータ

表B-4 OLS_LABEL_DOMINATESのパラメータ

パラメータ 説明

policy_name

セッション・ラベルの支配を確認する必要があるOracle Label Securityポリシーの名前。ポリシーの既存のラベル値を検索するには、ALL_SA_LABELSビューのPOLICY_NAMEおよびLABEL列を問い合せます。

label

支配を確認する必要があるベース・ラベル。

次の例では、hr_ols_polポリシーのセッション・ラベルにより、hsラベルが支配されるか、等しくなるかどうかを確認します。

SELECT OLS_LABEL_DOMINATES ('hr_ols_pol', 'hs') FROM DUAL;

OLS_LABEL_DOMINATES('HR_OLS_POL','HS')
--------------------------------------
                                     0

この例では、Oracle Data RedactionポリシーでOLS_LABEL_DOMINATESファンクションを使用する方法を示しています。

BEGIN
 DBMS_REDACT.ADD_POLICY(
   object_schema   => 'oe', 
   object_name     => 'customers', 
   column_name     => 'customer_id',
   policy_name     => 'redact_cust_user_ids', 
   function_type   => DBMS_REDACT.FULL,
   expression      => 'OLS_LABEL_DOMINATES(''hr_ols_pol'', ''hs'') = 0');
END;
/

次の例では、Oracle Database Vaultルール定義でOLS_LABEL_DOMINATESファンクションを使用する方法を示しています。

EXEC DBMS_MACADM.CREATE_RULE('Check OLS Factor', 'OLS_LABEL_DOMINATES(''hr_ols_pol'', ''hs'') = 1');

関連項目:

  • Data Redactionの詳細は、『Oracle Database Advanced Securityガイド』を参照してください

  • Database Vaultのレルムの詳細は、『Oracle Database Vault管理者ガイド』を参照してください

OLS_STRICTLY_DOMINATESスタンドアロン・ファンクション

OLS_STRICTLY_DOMINATES (OLS_S_DOM) ファンクションは、label1label2を支配していて、両者が等しくない場合は1 (TRUE)を戻します。

構文

OLS_STRICTLY_DOMINATES (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN INTEGER; 

パラメータ

表B-5 OLS_STRICTLY_DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SELECT OLS_STRICTLY_DOMINATES ('1111', '1112') FROM DUAL;

OLS_STRICTLY_DOMINATES('1111','1112')
-------------------------------------
                                    0

注意:

古いOLSファンクションであるSTRICTLY_DOMINATESおよびS_DOMは、Oracle Database 12cリリース1 (12.1)では非推奨です。

このリリースでは古いファンクションを引き続き使用できますが、かわりにOLS_STRICTLY_DOMINATESおよびOLS_S_DOMファンクションを使用することをお薦めします。新しいファンクション名を使用すると、他のデータベース・コンポーネントと名前が競合する可能性が回避されます。

OLS_DOMINATED_BYスタンドアロン・ファンクション

OLS_DOMINATED_BY (OLS_DOM_BY)ファンクションは、label1label2に支配されている場合は1 (TRUE)を戻します。

構文

OLS_DOMINATED_BY (
  label1          IN NUMBER,
  label2          IN NUMBER)
RETURN INTEGER;

パラメータ

表B-6 OLS_STRICTLY_DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SELECT OLS_DOMINATED_BY ('1111', '1112') FROM DUAL;

OLS_DOMINATED_BY('1111','1112')
-------------------------------
                              1

注意:

古いOLSファンクションであるDOMINATED_BYおよびDOM_BYは、Oracle Database 12cリリース1 (12.1)では非推奨です。

このリリースでは古いファンクションを引き続き使用できますが、かわりにOLS_DOMINATED_BYおよびOLS_DOM_BYファンクションを使用することをお薦めします。新しいファンクション名を使用すると、他のデータベース・コンポーネントと名前が競合する可能性が回避されます。

OLS_STRICTLY_DOMINATED_BYスタンドアロン・ファンクション

OLS_STRICTLY_DOMINATED_BY (OLS_S_DOM_BY)ファンクションは、label1label2に支配されていて、両者が等しくない場合は1 (TRUE)を戻します。

構文

OLS_STRICTLY_DOMINATED_BY (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN INTEGER; 

パラメータ

表B-7 OLS_DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SELECT OLS_STRICTLY_DOMINATES ('1111', '1112') FROM DUAL;

OLS_STRICTLY_DOMINATES('1111','1112')
-------------------------------------
                                    0

注意:

古いOLSファンクションであるSTRICTLY_DOMINATED_BYおよびS_DOM_BYは、Oracle Database 12cリリース1 (12.1)では非推奨です。

このリリースでは古いファンクションを引き続き使用できますが、かわりにOLS_STRICTLY_DOMINATED_BYおよびOLS_S_DOM_BYファンクションを使用することをお薦めします。新しいファンクション名を使用すると、他のデータベース・コンポーネントと名前が競合する可能性が回避されます。

SA_UTL.DOMINATES

SA_UTL.DOMINATESファンクションは、label1label2を支配する場合、または指定のOLSポリシーのセッション・ラベルがlabelを支配する場合はTRUEを戻します。

構文

SA_UTL.DOMINATES (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN BOOLEAN; 

構文

SA_UTL.DOMINATES (
  ols_policy_name  IN VARCHAR2,
  label            IN VARCHAR2) 
RETURN BOOLEAN; 

パラメータ

表B-8 SA_UTL.DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SET SERVEROUTPUT ON
BEGIN 
 IF SA_UTL.DOMINATES(1111, 1112)
  THEN DBMS_OUTPUT.PUT_LINE('Label 1111 dominates label 1112.');
 ELSE 
  DBMS_OUTPUT.PUT_LINE('Label 1112 dominates label 1111.'); 
 END IF; 
END;
/

Label 1112 dominates label 1111.

注意:

Oracle Label Securityポリシー名およびラベルを入力として受け取る2番目のSA_UTL.DOMINATESファンクションは、Oracle Database 12cリリース1 (12.1)では非推奨です。

このファンクションは引き続き使用できますが、Oracle Data RedactionおよびOracle Database Vaultの条件とともに使用することはできません。かわりにOLS_LABEL_DOMINATESファンクションを使用することをお薦めします。

NUMBERデータ型を使用する最初のSA_UTL.DOMINATESファンクションは、非推奨ではありません。

SA_UTL.STRICTLY_DOMINATES

SA_UTL.STRICTLY_DOMINATESファンクションは、label1label2を支配していて、両者が等しくない場合はTRUEを戻します。

構文

SA_UTL.STRICTLY_DOMINATES (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN BOOLEAN; 

パラメータ

表B-9 SA_UTL.STRICTLY_DOMINATESのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SET SERVEROUTPUT ON
BEGIN 
 IF SA_UTL.STRICTLY_DOMINATES(1111, 1112)
  THEN DBMS_OUTPUT.PUT_LINE('Label 1111 strictly dominates label 1112.');
 ELSE 
  DBMS_OUTPUT.PUT_LINE('Label 1112 strictly dominates label 1111.'); 
 END IF; 
END;
/

Label 1112 strictly dominates label 1111.

SA_UTL.DOMINATED_BY

SA_UTL.DOMINATED_BYファンクションは、label1label2に支配されている場合はTRUEを戻します。

構文

SA_UTL.DOMINATED_BY (
  label1          IN NUMBER,
  label2          IN NUMBER) 
RETURN BOOLEAN;

パラメータ

表B-10 SA_UTL.DOMINATED_BYのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SET SERVEROUTPUT ON
BEGIN 
 IF SA_UTL.DOMINATED_BY(1111, 1112)
  THEN DBMS_OUTPUT.PUT_LINE('Label 1111 is dominated by label 1112.');
 ELSE 
  DBMS_OUTPUT.PUT_LINE('Label 1112 is dominated by label 1111.'); 
 END IF; 
END;
/

Label 1111 is dominated by label 1112.

SA_UTL.STRICTLY_DOMINATED_BY

SA_UTL.STRICTLY_DOMINATED_BYファンクションは、label1label2に支配されていて、両者が等しくない場合はTRUEを戻します。

構文

SA_UTL.STRICTLY_DOMINATED_BY (
  label1          IN NUMBER,
  label2          IN NUMBER)
RETURN BOOLEAN;

パラメータ

表B-11 SA_UTL.STRICTLY_DOMINATED_BYのパラメータ

パラメータ 説明

label1

確認する最初のラベル。既存のラベル値を検索するには、ALL_SA_LABELSビューのLABELおよびTAG列を問い合せます。

label2

確認する2番目のラベル。

次の例では、既存のラベル・タグ11111112を比較しています。

SET SERVEROUTPUT ON
BEGIN 
 IF SA_UTL.STRICTLY_DOMINATED_BY(1111, 1112)
  THEN DBMS_OUTPUT.PUT_LINE('Label 1111 is strictly dominated by label 1112.');
 ELSE 
  DBMS_OUTPUT.PUT_LINE('Label 1112 is strictly dominated by label 1111.'); 
 END IF; 
END;
/

Label 1111 is strictly dominated by label 1112.

監査対象のOracle Label Securityセッション・ラベルの問合せ

統合された監査証跡を使用して、Oracle Label Securityなど、様々な監査ソースから情報を取得できます。

内容は次のとおりです。

監査対象のOracle Label Securityセッション・ラベルの問合せについて

統合監査ポリシーを作成して、OLS監査を構成する必要があります。

OLS監査により、OLSポリシーの有効化や無効化などの追加のイベントを監査できます。

監査証跡で取得されるセッション・ラベルは、UNIFIED_AUDIT_TRAILビューのAPPLICATION_CONTEXTS列に格納されます。LBACSYS.ORA_GET_AUDITED_LABELファンクションを使用して、APPLICATION_CONTEXTS列に格納されているセッション・ラベルを取得できます。このファンクションは、UNIFIED_AUDIT_TRAIL.APPLICATION_CONTEXTS列値、およびOracle Label Securityポリシー名を引数として受け入れ、指定したポリシーの列に格納されているセッション・ラベルを返します。

統合監査証跡でのOLS監査の構成および使用の詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

ORA_GET_AUDITED_LABELファンクション

ORA_GET_AUDITED_LABELファンクションは、指定されたOLSポリシーおよびAPPLICATION_CONTEXTS列値の監査済セッション・ラベルを戻します。

AUDIT_VIEWERロールには、ORA_GET_AUDITED_LABELファンクションでのEXECUTE権限があります。

構文

ORA_GET_AUDITED_LABEL (
  appctx_col_value   IN VARCHAR2,
  ols_policy_name    IN VARCHAR2)
RETURN VARCHAR2;

パラメータ

表B-12 ORA_GET_AUDITED_LABELのパラメータ

パラメータ 説明

appctx_col_value

UNIFIED_AUDIT_TRAIL.APPLICATION_CONTEXTS列の値。

policy_name

ラベル・セキュリティ・ポリシー名。

次の例では、hr_ols_polポリシーの監査済セッション・ラベルを戻します。

SELECT ORA_GET_AUDITED_LABEL ('cust_ctx', 'hr_ols_pol') FROM DUAL;

ORA_GET_AUDITED_LABEL('X','HR_OLS_POL')
---------------------------------------
                                     HS

セッション・ラベル設定用のOracle Call Interface

Oracle Call Interface (OCI)を使用して、セッション・ラベルを設定できます。

内容は次のとおりです。

Oracle Call Interfaceを使用したセッション・ラベルの設定について

Oracle Call Interface (OCI)を使用して接続する場合は、SYS_CONTEXT変数を使用してセッション・ラベルと行ラベルを初期化できます。

OCIAttrSetファンクションを使用して変数を設定し、外部で初期化されたSYS_CONTEXT変数を初期化できます。これらが使用できるのは、Oracle Label Securityが有効な場合です。

各ポリシーには、SA$policy_name_Xという名前のSYS_CONTEXTがあります。これらの2つの変数INITIAL_LABELおよびINITIAL_ROW_LABELを設定できます。

新規の値をユーザーの認証の範囲内で有効なラベルに設定すると、ユーザー用に格納されているデフォルト値のかわりにその値が使用されます。これは、リモート接続に使用されるのと同じメカニズムです。

Oracle Call Interfaceを使用したセッション・ラベルの設定

Oracle Call Interfaceを使用して、セッション・ラベルを設定できます。

  1. OCI_ATTR_APPCTX_SIZEを指定してOCIAttrSetをコールし、コンテキストの配列サイズを任意の数のコンテキスト属性で初期化します。
    OCIAttrSet(session, OCI_HTYPE_SESSION, 
                     (dvoid *)&size, (ub4)0, OCI_ATTR_APPCTX_SIZE, error_handle); 
     

    これにより、OCIAttrSetの追加属性が定義されます。

    サイズはub4型であることに注意してください。

  2. OCI_ATTR_APPCTX_LISTを指定してOCIAttrGetをコールし、セッションに対するアプリケーション・コンテキスト・リスト記述子のハンドルを取得します。
    OCIAttrGet(session, OCI_HTYPE_SESSION, 
                   (dvoid *)&ctxl_desc, (ub4)0, OCI_ATTR_APPCTX_LIST, error_handle);
    

    ctxl_descは(OCIParam *)型であることに注意してください。

  3. アプリケーション・コンテキスト・リスト記述子を指定してOCIParamGetをコールし、i-番目のアプリケーション・コンテキストの個々の記述子を取得します。
    OCIParamGet(ctxl_desc, OCI_DTYPE_PARAM, error_handle,(dvoid **)&ctx_desc, i);  
    

    ctx_descは(OCIParam *)型であることに注意してください。

  4. 3つの新規属性OCI_ATTR_APPCTX_NAMEOCI_ATTR_APPCTX_ATTRおよびOCI_ATTR_APPCTX_VALUEをそれぞれ指定してOCIAttrSetをコールし、アプリケーション・コンテキスト内で適切な値を設定します。
    OCIAttrSet(ctx_desc, OCI_DTYPE_PARAM,
                     (dvoid *)ctx_name, sizeof(ctx_name), OCI_ATTR_APPCTX_NAME,
                     error_handle);  
    
    OCIAttrSet(ctx_desc, OCI_DTYPE_PARAM,
                     (dvoid *)attr_name, sizeof(attr_name), OCI_ATTR_APPCTX_ATTR,
                     error_handle);  
    
    OCIAttrSet(ctx_desc, OCI_DTYPE_PARAM,
                     (dvoid *)value, sizeof(value), OCI_ATTR_APPCTX_VALUE,
                     error_handle);  
    

    アプリケーション・コンテキストの操作はVARCHAR2型に基づいているため、サポートされるのは文字型のみであることに注意してください。

例: SYS_CONTEXTファンクションによるOracle Call Interfaceの使用

外部化されたSYS_CONTEXTファンクションをOracle Label Securityで使用するOCIコールを作成できます。

例B-1に、その方法を示します。

例B-1 OLSでSYS_CONTEXTを外部化するためのOCIの使用

#ifdef RCSID
static char *RCSid =
   "$Header: ext_mls.c 09-may-00.10:07:08 jdoe Exp $ ";
#endif /* RCSID */

/* Copyright (c) Oracle Corporation 1999, 2000. All Rights Reserved. */

/*

   NAME
ext_mls.c - externalized SYS_CONTEXT with Label Security

   DESCRIPTION
Run olsdemo.sql script before executing this example.
Usage: <executable obtained with .c file> <user_name> <password> <session-initial-label
Example: avg_sal sa_demo sa_demo L3:M,E:D10

   PUBLIC FUNCTION(S)
<list of external functions declared/defined - with one-line descriptions>

   PRIVATE FUNCTION(S)
<list of static functions defined in .c file - with one-line descriptions>

   RETURNS
The average salary in the EMP table of the SA_DEMO schema querying as the specified user with the specified session label.

   NOTES
<other useful comments, qualifications, and so on>

   MODIFIED   (MM/DD/YY)
jlev      09/18/03 - cleanup
jdoe      05/09/00 - cleanup
   jdoe      10/13/99 - standalone OCI program to test MLS SYS_CONTEXT
   jdoe      10/13/99 - Creation

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>

static OCIEnv *envhp;
static OCIError *errhp;

int main(/*_ int argc, char *argv[] _*/);

/* get and print error */
static void checkerr(/*_OCIError *errhp, sword status _*/);
/* print error */
static void printerr(char *call);
static sword status;

/* return the average of employees' salary */
static CONST text *const selectstmt = (text *)
     "select avg(sal) from sa_demo.emp";
 
int main(argc, argv)
int argc;
char *argv[];
{
  OCISession *authp = (OCISession *) 0;
  OCIServer *srvhp;
  OCISvcCtx *svchp;
  OCIDefine *defnp = (OCIDefine *) 0;
  dvoid *parmdp;
  ub4 ctxsize;
  OCIParam *ctxldesc;
  OCIParam *ctxedesc;
  OCIStmt *stmtp = (OCIStmt *) 0;
  ub4 avg_sal = 0;
  sword status;

  if (OCIInitialize((ub4) OCI_DEFAULT, (dvoid *) 0,
                    (dvoid * (*)(dvoid *, size_t)) 0,
                    (dvoid * (*)(dvoid *, dvoid *, size_t)) 0,
                    (void (*)(dvoid *, dvoid *)) 0))
    printerr("OCIInitialize");

  if (OCIEnvInit((OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0, (dvoid **) 0))
    printerr("OCIEnvInit");
  
  if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,
                     (size_t) 0, (dvoid **) 0))
    printerr("OCIHandleAlloc:OCI_HTYPE_ERROR");

  if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
                     (size_t) 0, (dvoid **) 0))
    printerr("OCIHandleAlloc:OCI_HTYPE_SERVER");

  if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
                     (size_t) 0, (dvoid **) 0))
    printerr("OCIHandleAlloc:OCI_HTYPE_SVCCTX");

  if (OCIServerAttach(srvhp, errhp, (text *) "", strlen(""), 0))
    printerr("OCIServerAttach");

  /* set attribute server context in the service context */
  if (OCIAttrSet((dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *) srvhp,
                 (ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp))
    printerr("OCIAttrSet:OCI_HTYPE_SVCCTX");

  if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &authp,
                     (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0))
    printerr("OCIHandleAlloc:OCI_HTYPE_SESSION");

  /* set application context to 1 */
  ctxsize = 1;

  /* set up app ctx buffer */
  if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, (dvoid *) &ctxsize,
                 (ub4) 0, (ub4) OCI_ATTR_APPCTX_SIZE, errhp))
    printerr("OCIAttrSet:OCI_ATTR_APPCTX_SIZE");

  /* retrieve the list descriptor */
  if (OCIAttrGet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,
                 (dvoid *) &ctxldesc, 0, OCI_ATTR_APPCTX_LIST, errhp))
    printerr("OCIAttrGet:OCI_ATTR_APPCTX_LIST");

  if (status = OCIParamGet(ctxldesc, OCI_DTYPE_PARAM, errhp,
                           (dvoid **) &ctxedesc, 1))
    {
      if (status == OCI_NO_DATA)
        {
          printf("No Data found!\n");
          exit(1);
        }
    }

  /* set context namespace to SA$<pol_name>_X */
  if (OCIAttrSet((dvoid *) ctxedesc, (ub4) OCI_DTYPE_PARAM,
                 (dvoid *) "SA$HUMAN_RESOURCES_X",
                 (ub4) strlen((char *) "SA$HUMAN_RESOURCES_X"),
                 (ub4) OCI_ATTR_APPCTX_NAME, errhp))
    printerr("OCIAttrSet:OCI_ATTR_APPCTX_NAME:SA$HUMAN_RESOURCES_X");

  /* set context attribute to INITIAL_LABEL */
  if (OCIAttrSet((dvoid *) ctxedesc, (ub4) OCI_DTYPE_PARAM,
                 (dvoid *) "INITIAL_LABEL",
                 (ub4) strlen((char *) "INITIAL_LABEL"),
                 (ub4) OCI_ATTR_APPCTX_ATTR, errhp))
    printerr("OCIAttrSet:OCI_DTYPE_PARAM:INITIAL_LABEL");

  /* set context value to argv[3] - initial label */
  if (OCIAttrSet((dvoid *) ctxedesc, (ub4) OCI_DTYPE_PARAM,
                 (dvoid *) argv[3],
                 (ub4) strlen((char *) argv[3]),
                 (ub4) OCI_ATTR_APPCTX_VALUE, errhp))
    printerr("OCIAttrSet:argv[3]");

  /* username first command line argument */
  if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, (dvoid *) argv[1],
                 (ub4) strlen((char *) argv[1]), (ub4) OCI_ATTR_USERNAME,
                 errhp))
    printerr("OCIAttrSet:username");

  /* password second command line argument */
  if (OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION, (dvoid *) argv[2],
                 (ub4) strlen((char *) argv[2]), (ub4) OCI_ATTR_PASSWORD,
                 errhp))
    printerr("OCIAttrSet:password");

  if (OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT))
    printerr("OCISessionBegin");

  if (OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) authp,
                 (ub4) 0, (ub4) OCI_ATTR_SESSION, errhp))
    printerr("OCIAttrSet:OCI_ATTR_SESSION");

  if (OCIHandleAlloc((dvoid *) envhp, (dvoid **) &stmtp, OCI_HTYPE_STMT,
                     0, 0))
    printerr("OCIHandleAlloc:OCI_HTYPE_STMT");

  if (OCIStmtPrepare(stmtp, errhp, (CONST OraText *) selectstmt,
                     (ub4) strlen((const char *) selectstmt),
                     (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))
    printerr("OCIStmtPrepare");

  if (OCIDefineByPos(stmtp, &defnp, errhp, (ub4) 1, (dvoid *) &avg_sal,
                     (sb4) sizeof(avg_sal), SQLT_INT, 0, 0, 0, OCI_DEFAULT))
    printerr("OCIDefineByPos");

  if (status = OCIStmtExecute(svchp, stmtp, errhp, 1, 0, NULL, NULL,
                              OCI_DEFAULT))
    {
      if (status == OCI_NO_DATA)
        {
          printf("No Data found!\n");
          exit(1);
        }
    }

  if (OCISessionEnd(svchp, errhp, authp, OCI_DEFAULT))
    printerr("OCISessionEnd");

  printf("average salary is: %d\n", avg_sal);
}

void checkerr(errhp, status)
     OCIError *errhp;
     sword status;
{
  text errbuf[512];
  sb4 errcode = 0;

  switch (status)
    {
    case OCI_ERROR:
      (void) OCIErrorGet((dvoid *) errhp, 1, NULL, &errcode, errbuf,
                         (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
      printf("Error - %.*s\n", 512, errbuf);
      break;
    default:
      break;
    }
}

void printerr(call)
     char *call;
{
  printf("Error: %s\n", call);
}
/* end of file ext_mls.c */