              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 1164.5   CAlling shareable images, privileged user services??        5 of 7
ADCA01::DATTESH                                     290 lines  22-NOV-1996 04:16
                    -< Our Source and Problem Explanation >-
--------------------------------------------------------------------------------
The following is modification of UWSS program in 'C' from sys$examples. It is
calling the 'PASCAL' procedures which have been listed in the kernel_table[]
array. The 'PASCAL' procedures in turn calls $setprv. 
The programs are compiled and linked with the standard options to make it
sharable and protected. The library is also installed. On execution of the
image using these libraries, we are getting the following error:

SYSTEM-F-NOSHRIMG, privileged sharable image cannot have outbound calls

It would be helpful if you could elaborate on the setting of bits in the
privilege mask directly, or provide us some pointers on documentation
explaining this. Ofcourse, we are downloading the Internals and Data structure
manual and would be searching for this info in that manual.

/**************  The C program         ***************************/


/* And now, on with the program... */

#include <ssdef.h>
#include <chfdef.h>
#include <builtins.h>
#include <lib$routines.h>
#include <prdef.h>
#include <plvdef.h>


/*
** To make things easy, the number and name of the user-written system
** services must be known at compile time.  So first define the number
** of services (kernel and exec) and allocate the routine lists, which
** in C-language terms are arrays of pointers to functions returning
** ints.
*/


/* "Forward routine" declarations */
int     mdv$prv_set,
        mdv$prv_gset,
        mdv$prv_init;
int     rundown_handler();

/* Kernel and exec routine lists: */
int (*(kernel_table[]))() = {
        mdv$prv_set,
        mdv$prv_gset,
        mdv$prv_init};

/*
** The next two defines allow the kernel and executive routine counts
** to be filled in automatically after lists have been declared for
** kernel and exec mode.  They must be placed before the PLV
** declaration and initialization, and for this module will be
** functionally equivalent to:
**
** #define KERNEL_ROUTINE_COUNT 3
** #define EXEC_ROUTINE_COUNT 1
** 
*/

#define EXEC_ROUTINE_COUNT   0
#define KERNEL_ROUTINE_COUNT sizeof(kernel_table)/sizeof(int *)

/*
** Now build and initialize the PLV structure.  Since the PLV must have
** the VEC psect attribute, and must be the first thing in that psect,
** we use the strict external ref-def model which allows us to put the
** PLV structure in its own psect.  This is like the globaldef
** extension in VAX C, where you can specify in what psect a global
** symbol may be found; unlike globaldef, it allows the declaration
** itself to be ANSI-compliant.  Note that the initialization here
** relies on the change-mode-specific portion (plv$r_cmod_data) of the
** PLV being declared before the portions of the PLV which are specific
** to message vector PLVs (plv$r_msg_data) and system service intercept
** PLVs (plv$r_ssi_data).
**
*/

#ifdef __ALPHA
#pragma extern_model save
#pragma extern_model strict_refdef "USER_SERVICES"
#endif
extern const PLV user_services = {
        PLV$C_TYP_CMOD,         /* type */
        0,                      /* version */
        {
        {KERNEL_ROUTINE_COUNT,   /* # of kernel routines */
        EXEC_ROUTINE_COUNT,     /* # of exec routines */
        kernel_table,           /* kernel routine list */
        0, 			/* exec routine list */
        rundown_handler,        /* kernel rundown handler */
        rundown_handler,        /* exec rundown handler */
        0,                      /* no RMS dispatcher */
        0,                      /* kernel routine flags */
        0}                     /* exec routine flags */
        }
        };
#ifdef __ALPHA
#pragma extern_model restore
#endif

/*
** And now, the service routines.  The routines in this example
** execute no instructions which would require privilege to complete,
** but they give different results when run privileged than they would
** if run from a non-privileged shareable image.  Each routine will
** expects to be passed a pointer to an array of 2 longwords.  The
** first longword will be set by the service routine to contain the
** low 32-bits of the processor status register, from which a caller
** can verify that the service routine is executing in the proper mode
** (kernel or exec).  The second longword is then set to a unique
** integer (1 for first_service, and so on up to 4) to verify that the
** correct service routine has been called.
**
** Each routine will verify that it can write to the longword array in
** the previous mode, since we're running in one of the inner modes.
** If a bogus address were passed (either an inaccessible address,
** causing an access violation, or an address accessible in an inner
** mode that shouldn't be accessible in user mode), then without this
** check, either the process would get blown away (exec mode) or the
** system would crash (in kernel mode, right away if an accvio or
** later if system space were corrupted).  Clearly, neither failure
** mode is desirable.  Note that the use of the single PROBEW PAL call
** for previous mode is enough because only a single contiguous pair
** of longword data (equivalent to a single quadword datum) will be
** stored.  For storage of larger amounts of data which may cross more
** than one page boundary, more stringent checking is required.
**
** One final note on the service routines.  As a security precaution,
** protected shareable images aren't allowed to call other shareable
** images, unless they too are installed protected.  Watch your calls
** (including implicit ones) to external routines!  They must either
** be linked (from object files or libraries) into your image, or be
** in other protected images.  If you fail to heed this warning, the
** image activator will 'kindly' remind you with the error:
**
** SYSTEM-F-NOSHRIMG, privileged shareable image cannot have outbound calls
*/


/*
** Our kernel and exec rundown handlers are one and the same.
** The rundown handler is invoked before any system rundown
** is performed.
**
** This routine is provided simply as a placeholder for a
** real rundown handler.  A user-written rundown handler
** should not invoke any RMS services or RTL routines, and
** must not signal any exceptions.  User-written rundown
** handlers can invoke most system services except those
** that use RMS (i.e.  $PUTMSG).
*/
int rundown_handler()
{
    return SS$_NORMAL;			/* Indicate success */
}



/*****************  The PASCAL program  ******************************/

[ ASYNCHRONOUS ,  GLOBAL ]
FUNCTION mdv$prv_set(
	oldprv : $UQUAD;
	newprv : $UQUAD;
	FirstParam,
	SecondParam : INTEGER) : INTEGER;
 
    {
    FUNCTIONAL DESCRIPTION: 
     
    FORMAL PARAMETERS: 
     
	    %[description_or_none]%
     
    IMPLICIT INPUTS:
     
	    %[description_or_none]%
     
    IMPLICIT OUTPUTS:
     
	    %[description_or_none]%
     
    ROUTINE VALUE:
     
	    %[description_or_none]%
     
    SIDE EFFECTS:
     
	    %[description_or_none]%
    }
VAR
    LocalParam : INTEGER := 23896;
 
BEGIN
  IF (FirstParam = GlobalParam ) AND ( SecondParam = LocalParam ) THEN
  BEGIN   
    mdv$prv_set := $setprv( enbflg := 0,
			    prmflg := 0,	
			    prvadr := oldprv);

    mdv$prv_set := $setprv( enbflg := 1,
			    prmflg := 0,
			    prvadr := newprv)
  END ELSE Mdv$Prv_Set := SS$_NOPRIV;
END;


[ ASYNCHRONOUS ,  GLOBAL ]
FUNCTION mdv$prv_gset(
    VAR	oldprv : $UQUAD;
	newprv : $UQUAD;
        remove_old : Boolean;
	FirstParam,
	SecondParam  : INTEGER ) : INTEGER;
VAR
	LocalParam : INTEGER := 23896;

BEGIN
  IF ( FirstParam = GlobalParam ) AND ( SecondParam = LocalParam ) THEN
  BEGIN
    mdv$prv_gset := $setprv( enbflg:= 1,
			    prmflg := 0,
			    prvadr := newprv,
			    prvprv := oldprv);


    IF remove_old Then
    Begin
        { Remove previous privileges }
        mdv$prv_gset := $setprv( enbflg := 0,
			        prmflg := 0,	
			        prvadr := oldprv);

        { Re-force new privileges }
        mdv$prv_gset := $setprv( enbflg := 1,
			        prmflg := 0,
			        prvadr := newprv);
    END; 
  END ELSE Mdv$Prv_Gset := SS$_NOPRIV;
END;


[GLOBAL]
FUNCTION mdv$prv_init ( FirstParam, SecondParam : INTEGER ) : INTEGER;
VAR
    LocalParam 	: INTEGER := 23896;
    rstat	: INTEGER; 
    {
    FUNCTIONAL DESCRIPTION: 
     
	    %[tbs]%
     
    FORMAL PARAMETERS: 
     
	    %[description_or_none]%
     
    IMPLICIT INPUTS:
     
	    %[description_or_none]%
     
    IMPLICIT OUTPUTS:
     
	    %[description_or_none]%
     
    ROUTINE VALUE:
     
	    %[description_or_none]%
     
    SIDE EFFECTS:
     
	    %[description_or_none]%
    }
 
BEGIN
  IF ( FirstParam = GlobalParam ) AND ( SecondParam = LocalParam ) THEN
    mdv$prv_init := $setprv(enbflg := 1,
			    prmflg := 0,	
			    prvadr := prv$m_sysprv +
				      prv$m_syslck +
				      prv$m_cmkrnl +
				      prv$m_sysgbl +
				      prv$m_oper   +
				      prv$m_tmpmbx +
				      prv$m_netmbx)
  ELSE Mdv$Prv_Init := SS$_NOPRIV;
END;

END.
    
