From:	SMTP%"bol@adv.magwien.gv.at" 11-AUG-1997 18:32:05.45
To:	everhart@gce.com
CC:	
Subj:	New VMS tools

Return-Path: bol@adv.magwien.gv.at
Received: by arisia.gce.com (UCX V4.1-12C, OpenVMS V7.1 VAX);
	Mon, 11 Aug 1997 18:07:39 -0400
Received: from mozart.adv.magwien.gv.at (mozart.adv.magwien.gv.at [141.203.2.173]) by bort.mv.net (8.8.5/mem-951016) with SMTP id HAA18921; Mon, 11 Aug 1997 07:53:14 -0400 (EDT)
Received: by mozart.adv.magwien.gv.at id AA10185
  (5.65c8+/MagwienServer(pfp)2.3 for everhart@gce.com); Mon, 11 Aug 1997 13:52:04 +0200
Received: from marmeladinger.adv.magwien.gv.at by adv.magwien.gv.at (5.65c8+/MagwienSilly(pfp&stg)1.2/3.14) id AA02846; Mon, 11 Aug 1997 13:47:52 +0200
Received: from marmeladinger.adv.magwien.gv.at by marmeladinger.adv.magwien.gv.at with SMTP id MAA01422
  (8.8.5/MagwienClient(pfp)2.4 for adv.magwien.gv.at); Mon, 11 Aug 1997 12:46:47 +0100 (WET DST)
Sender: bol@adv.magwien.gv.at
Message-Id: <33EEFB84.794B@adv.magwien.gv.at>
Date: Mon, 11 Aug 1997 12:46:46 +0100
From: Ferry Bolhar-Nordenkampf <bol@adv.magwien.gv.at>
Organization: Magistrat der Stadt Wien MA-14
X-Mailer: Mozilla 3.0 (X11; I; OSF1 V4.0 alpha)
Mime-Version: 1.0
To: everhart@gce.com
Subject: New VMS tools
Content-Type: multipart/mixed; boundary="------------15FB59E21CFB"
X-Charset: LATIN1
X-Char-Esc: 29
Errors-To: bol@marmeladinger.adv.magwien.gv.at
X-Doublesendmail-From: bol@adv.magwien.gv.at
X-Doublesendmail-To: everhart@gce.com

This is a multi-part message in MIME format.

--------------15FB59E21CFB
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by marmeladinger.adv.magwien.gv.at id MAA01422

Hi Glenn,

> If you'd be willing to email these tools to me I'd think they'd be
> good to put on the fall '97 sigtapes, which I edit. Email to
> everhart@gce.com preferably (mftu encoded zip is best but I'll
> decode most anything) or whatever...
>
> Thanks
> Glenn Everhart
> (also everhart@mitre.org)

I've added the sources of these tools as an attachment to this mail - if
you
encounter problems, please let me know.

Best greetings, Ferry

--=20
Ing. Ferry Bolh=E1r-Nordenkampf
Magistrat der Stadt Wien (MA-14)	A - 1010 Vienna (Austria)
Phone: 0222/4000/98632			E-Mail: bol@adv.magwien.gv.at

"Wenn hier einer schuld ist, dann immer nur der Computer."

--------------15FB59E21CFB
Content-Type: text/plain; charset=iso-8859-1; name="adv_pipe011.mai"
Content-Disposition: inline; filename="adv_pipe011.mai"
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by marmeladinger.adv.magwien.gv.at id MAA01422


	ADV_PIPE V1.1
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D


	This mail contains the following files (in this order):

	$$$README.DOC		General information about ADV_PIPE. As its
				name indicates, read this file before
				installing ADV_PIPE. Please ignore the
				information concerning saveset processing.

	ADV_PIPE.COM		Login command procedure.

	ADV_PIPE_LOGS.COM	Procedure to define private logicals.

	ADV_PIPE_STARTUP.COM	System startup procedure.

	ADV_PIPE_SYSTARTUP.COM	Procedure to define system-wide logicals.
=09
	INSTALL.COM		Installation procedure for ADV_PIPE.

	ADV_PIPE.C		The C source.

	ADV_PIPE.HLP		Online help file.

	ADV_PIPE.CLD		Command definitions.

	ADV_PIPE_AXP.OPT	Linker option file for Alpha.

	ADV_PIPE_VAX_D.OPT	Linker option file for VAX with DEC C

	ADV_PIPE_VAX_V.OPT	Linker option file for VAX with VAX C

	(Total of 12 files.)


	You need a VAX C or DEC C compiler to build ADV_PIPE.

	All files are separated with a header line containing a
	form feed (ASCII 12) character.

	After extracting all files from this mail in a directory
	go to this directory and type @INSTALL.


	Hope you'll find it useful. Have fun with ADV_PIPE!

					Greetings, Ferry


=0C---------------------->>> #1: $$$README.DOC <<<----------------------


	ADV_PIPE V1.0
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	ADV_PIPE allows you to supply U*I-like separators and redirectors
	to concatenate and combinate more DCL commands in a single command
	line.



	1) Installation Requirements
	----------------------------

	ADV_PIPE requires VAX/VMS V5.4 or higher or OpenVMS AXP V1.5 or
	higher. No additional software is required for installatio and use.
	The following resources are required as well:

	User-local installation:

	Resource		VAX	Alpha
	-------------------------------------
	Blocks in [.ADV_PIPE]	140	180



	System-wide installation:

	Resource		VAX	Alpha
	-------------------------------------
	Blocks on system disk	24	38
	Global sections		 1	 1
	Global pages		10	20



	2) Installation
	---------------

	To install ADV_PIPE:

	o) Create a temporary directory (CREATE/DIRECTORY [.TMP]).
=09
	o) Copy the product saveset into this directory and place yourself
	   therein (SET DEFAULT).

	o) Extract the backup savset:

	   $ BACKUP ADV_PIPE010.SAV/SAVE []

	o) Call the installation procedure.

	   $ @INSTALL

	The installation procedure offers a menu with the following
	selections:

	1) Install the software local only
	2) Recompile & install the software local only
	3) Install the software system-wide
	4) Recompile & install the software system-wide

	The first and second choice perform a user-local installation.
	No privileges are required for this type of installation. You
	must specify a directory wherein the [.ADV_PIPE] subdirectory=20
	is created. All product files are placed in this directory.

	A system-wide installation makes the product available on the
	entire system (or VMScluster) which requires, of course, privi-
	leges (SYSPRV, SYSNAM and CMKRNL). You must have these privileges,
	otherwise the installation procedure doesn't display these
	options. A system-wide installation copies all required files
	to the approbiate system directories and updates the CLI tables,
	system startup database and online-help library.

	When you have changes made on the sources, you must recompile
	the program. Otherwise, it is sufficient when you link it. Note
	that you need a C compiler (DEC C or VAX C) to recompile the
	sources. If the installation procedure determines that you have
	no C compiler installed, the choices for recompilation are not
	displayed.

	After selecting the desired installation option, the procedure
	starts. When the message

	"Installation completed successfully"

	is displayed, the installation has completed. You may now
	delete the contents of the temporary directory holding the
	extracted saveset files.



	3) Startup
	----------

	User-local:

	For user-local installation, a file named ADV_PIPE.COM is
	created in the [.ADV_PIPE] subdirectory during installation.
	This procedure should run as part of your login. It loads
	the PIPE command verb from the CLI definition file ADV_PIPE.CLD
	and updates the logical SYS$HELP in your job table to point to
	SYS$HELP as well as to [.ADV_PIPE]ADV_PIPE.HLB which contains
	online help to ADV_PIPE.

	Some of ADV_PIPE's behaviour is controlled by logicals names.
	You can use the procedure [.ADV_PIPE]ADV_PIPE_LOGS.COM to define
	it. Look at this file, it contains a detailled description of
	the available names.=09


	System-wide:

	ADV_PIPE is started automatically during the installation. The
	startup procedure is inserted into the system startup database
	(phase =3D LPMAIN, mode =3D DIRECT). For a manual start, enter:

	$ @SYS$STARTUP:ADV_PIPE_STARTUP

	You must execute this command on every cluster member in a
	VMScluster.

	You need SYSPRV and CMKRNL privileges to run the startup
	procedure.

	Some of ADV_PIPE's behaviour is controlled by logicals names.
	You can use the procedure SYS$MANAGER:ADV_PIPE_SYSTARTUP.COM
	to define them. Look at this file, it contains a detailled
	description of the available names.=09



	4) Usage
	--------

	ADV_PIPE provides its own online help which contains a
	detailled description. Type HELP PIPE for more.



	5) File created by the installation
	-----------------------------------

	Local-only:

	[.ADV_PIPE]ADV_PIPE.EXE			PIPE Image

	[.ADV_PIPE]ADV_PIPE.CLD			Command definition

	[.ADV_PIPE]ADV_PIPE.HLB			Help library

	[.ADV_PIPE]ADV_PIPE.COM			Local startup (login) procedure

	[.ADV_PIPE]ADV_PIPE_LOGS.COM		To define job-widelogicals



	System-wide:

	SYS$SYSTEM:ADV_PIPE.EXE			PIPE Image.

	SYS$STARTUP:ADV_PIPE_STARTUP.COM	Startup procedure.

	SYS$MANAGER:ADV_PIPE_SYSTARTUP.COM	To define system-logicals



	6) Further information
	----------------------

	The original version of PIPE was written by Ken Wallewein.
	This old version was written in MACRO-32 and had some bugs.
	It also did not provide the following features, which are
	available in this new C-version:
=09
	o) Background processing (&);

	o) Logical names ADV_PIPE_NOSYMBOLS, ADV_PIPE_NOLOGICALS
	   and ADV_PIPE_NOTIFY to control options when spawning
	   subprocesses (they correspond to SPAWN's /NOSYMBOLS,
	   /NOLOGICALS und /NOTIFY qualifiers),

	o) Logical name ADV_PIPE_DOUBLE_SEMI to control the
	   interpretation of the semicolon (;),

	o) Logical name ADV_PIPE_DCL_PARSE to decide whether
	   every command within a pipe is first parsed by DCL
	   before the pipe is created.


	Enhancements in future versions are:

	o) Operators && and || to force a conditional, sequential
	   execution of commands;

	o) Handling of the a single ampersand character, followed
	   by an alphabetical character - this may be a DCL symbol
	   substitution as well. A logical name ADV_PIPE_NOAMPER_SUBST
	   will control ADV_PIPE's behaviour in this case;

	o) Command groups (commands in parentheses).


					Vienna, October 1995

					Ing. Ferry Bolh=E1r-Nordenkampf,
					Municipality of Vienna
					MA 14 - ADV
					A-1010 Wien (Vienna)
					E-mail: bol@adv.magwien.gv.at


	7) Copyright note
	-----------------

        This software is COPYRIGHT =A9 1993-1995, Municipality of
        City of Vienna. ALL RIGHTS RESERVED.

        Permission is granted for non-profit redistribution and use,
        provided that no changes are made in the sources and that
        this copyright notice remains intact.

        This software is provided "AS IS". The author, Ing. Ferry
        Bolh=E1r (bol@adv.magwien.gv.at) makes no representations or
        warranties with respect to this software.

=0C---------------------->>> #2: ADV_PIPE.COM <<<----------------------

$ !
$ ! Login procedure for ADV_PIPE
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D
$ !
$ ! ADV_PIPE V1.1
$ ! -------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! This file is used to make the PIPE command and ADV_PIPE's
$ ! online help known to the current process.
$ !
$ x =3D f$veri(0)
$ z =3D f$envi("PROCEDURE")
$ set comm adv_pipe
$ devdir =3D f$pars(z,,,"DEVICE") + f$pars(z,,,"DIRECTORY")
$ defi/job/nolog pipe_dir 'devdir'
$ hlp =3D f$trnl("HLP$LIBRARY")
$ if hlp .eqs. ""
$ then
$ defi/job hlp$library pipe_dir:adv_pipe
$ else
$ n =3D 1
$ L_1:
$ hlp =3D f$trnl("HLP$LIBRARY_''n'")
$ if hlp .nes. ""
$ then
$ n =3D n + 1
$ goto L_1
$ endi
$ defi/job/nolog hlp$library_'n' pipe_dir:adv_pipe
$ endi
$ file =3D "''devdir'adv_pipe_logs.com"
$ if f$sear (file) .nes. "" then @'file'
$ x =3D f$veri(x)
$ exit

=0C---------------------->>> #3: ADV_PIPE_LOGS.COM <<<-------------------=
---

$ !
$ ! ADV_PIPE_LOGS.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! ADV_PIPE V1.1
$ ! -------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! This file contains user-settable logicals to control PIPE's working
$ ! behaviour. If you want to define a logical, remove the leading exclam=
ation
$ ! point (!). If you want to undefine it, place the leading exclamation =
point
$ ! before the approbiate DEFINE command. The initial settings in this fi=
le are
$ ! a good choice to work with PIPE.
$ !
$ !
$ ! 1) ADV_PIPE_NOSYMBLS - do not pass DCL symbols to subprocesses. Same =
as
$ !    SPAWN/NOSYMBOLS in DCL. Recommended, since subprocess creation is =
faster.
$ !    Note that symbol substitution in PIPE's command line occurs in the
$ !    context of the main process, so there is no need to pass them to a=
ny
$ !    subprocess.
$ !
$ DEFINE/JOB/NOLOG ADV_PIPE_NOSYMBOLS 1
$ !
$ !
$ ! 2) ADV_PIPE_NOLOGICALS - do not pass per-process logical names to sub=
-
$ !    processes. Same as SPAWN/NOLOGICALS in DCL. Recommended, since sub=
-
$ !    process creation is faster. If you want to share logical names wit=
hin
$ !    your subprocesses, place them in the job logical name table (DEFIN=
E/JOB).
$ !
$ DEFINE/JOB/NOLOG ADV_PIPE_NOLOGICALS 1
$ !
$ !
$ ! 3) ADV_PIPE_NOTIFY - request notification whenever an asynchronuous s=
ub-
$ !    process created by PIPE completes. Same as SPAWN/NOWAIT/NOTIFY in =
DCL.
$ !    This name is used only for subprocesses running in background (spe=
cified
$ !    with the '&' operator). It is ignored for sequential subprocess
$ !    operations (';' operator) and when using PIPE non-interactively.
$ !
$ DEFINE/JOB/NOLOG ADV_PIPE_NOTIFY 1
$ !
$ !
$ ! 4) ADV_PIPE_DOUBLE_SEMI - controls PIPE's interpretation of the semic=
olon
$ !    (;) character:
$ !
$ !    If this name is *not* defined, a single semicolon is treated as se=
-
$ !    quential operator; when specifying a version number in an RMS file=
 name,
$ !    you must use the dot (.) character instead.
$ !=20
$ !    If this name *is* defined, a single semicolon character is not tre=
ated
$ !    as sequential operator; you'll have to specify 2 semicolons instea=
d (no
$ !    space is allowed beetween them). This allows you use the semicolon=
 in
$ !    RMS file names as usual.
$ !
$ !    Note that a single semicolon is always recognized as sequential op=
erator
$ !    when it is preeceded by one or more blanks or tabs.
$ !
$ !DEFINE/JOB/NOLOG ADV_PIPE_DOUBLE_SEMI 1
$ !
$ !
$ ! 5) ADV_PIPE_DCL_PARSE - if set, PIPE calls DCL to parse every command
$ !    before the subprocess is created and the command is passed to it. =
This
$ !    prevents the user to send unknown commands to piped subprocesses
$ !    which can result in unexpected loops or hangups when the pipe is b=
roken.
$ !    Note that with this feature, the DCL$PATH logical (VMS V6.2 or hig=
her)
$ !    will not work; you must define every foreign command as command sy=
mbol.
$ !
$ !    If you do not use pipes, you can disable this feature.
$ !
$ DEFINE/JOB/NOLOG ADV_PIPE_DCL_PARSE 1
$ !
$ !
$ ! 6) ADV_PIPE_DEBUG - print debugging information. For PIPE's developer=
s
$ !    only. Do not set it unless you want to receive many messages ;-)
$ !
$ !DEFINE/JOB/NOLOG ADV_PIPE_DEBUG 1
$ !
$ exit

=0C---------------------->>> #4: ADV_PIPE_STARTUP.COM <<<----------------=
------

$ !
$ ! ADV_PIPE_STARTUP.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! PIPE Version V1.1
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! Revision history:
$ !
$ ! 20-OCT-1993 BOL	V1.0 created.
$ ! 10-DEC-1995 BOL	V1.1 created.
$ !
$ prod_vers =3D "011"
$ !
$ i_v =3D "V1.1"
$ put =3D "writ sys$output"
$ sysdef =3D "defi/syst/exec/nolog"
$ on warn then goto ERROR_EXIT
$ !
$ put "%PIPE-I-START_BEG, startup for ADV_PIPE ''i_v' is running, please =
wait..."
$ prvprv =3D f$setp ("SYSPRV,SYSNAM,CMKRNL")
$ if .not. f$priv ("SYSPRV,SYSNAM,CMKRNL") then goto NO_PRIV
$ sysdef ADV_PIPE_ISHI 1
$ sysdef PIPE_DIR SYS$SYSTEM
$ file =3D "SYS$COMMON:[SYSEXE]ADV_PIPE.EXE"
$ gosu CHECK_INS
$ deas/syst/exec ADV_PIPE_ISHI
$ sysdef ADV_PIPE_ISDO "''prod_vers'"
$ ERROR_EXIT:
$ if f$trnl ("ADV_PIPE_ISDO") .eqs. ""
$ then put "%PIPE-E-NOTSTARTED, ADV_PIPE ''i_v' was not started!"
$ else put "%PIPE-I-START_END, startup for ADV_PIPE ''i_v' completed succ=
essfully"
$ endi
$ x =3D f$setp (prvprv)
$ file =3D f$sear ("SYS$MANAGER:ADV_PIPE_SYSTARTUP.COM")
$ if file .nes. "" then @'file'
$ exit
$ !
$ CHECK_INS:
$ if f$sear (file) .eqs. "" then goto NO_FILE
$ if f$file (file, "KNOWN") then inst remo 'file'
$ inst add/open/head 'file'
$ retu
$ NO_FILE:
$ put "%PIPE-F-ACCFAIL, failed to access ''file'"
$ goto ERROR_EXIT
$ NO_PRIV:
$ put "%PIPE-F-NOPRIV, insufficient privileges for startup"
$ goto ERROR_EXIT

=0C---------------------->>> #5: ADV_PIPE_SYSTARTUP.COM <<<--------------=
--------

$ !
$ ! ADV_PIPE_SYSTARTUP.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! ADV_PIPE V1.1
$ ! -------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! This file contains user-settable logicals to control PIPE's working
$ ! behaviour. If you want to define a logical, remove the leading exclam=
ation
$ ! point (!). If you want to undefine it, place the leading exclamation =
point
$ ! before the approbiate DEFINE command. The initial settings in this fi=
le are
$ ! a good choice to work with PIPE.
$ !
$ !
$ ! 1) ADV_PIPE_NOSYMBLS - do not pass DCL symbols to subprocesses. Same =
as
$ !    SPAWN/NOSYMBOLS in DCL. Recommended, since subprocess creation is =
faster.
$ !    Note that symbol substitution in PIPE's command line occurs in the
$ !    context of the main process, so there is no need to pass them to a=
ny
$ !    subprocess.
$ !
$ DEFINE/SYSTEM/NOLOG ADV_PIPE_NOSYMBOLS 1
$ !
$ !
$ ! 2) ADV_PIPE_NOLOGICALS - do not pass per-process logical names to sub=
-
$ !    processes. Same as SPAWN/NOLOGICALS in DCL. Recommended, since sub=
-
$ !    process creation is faster. If you want to share logical names wit=
hin
$ !    your subprocesses, place them in the job logical name table (DEFIN=
E/JOB).
$ !
$ DEFINE/SYSTEM/NOLOG ADV_PIPE_NOLOGICALS 1
$ !
$ !
$ ! 3) ADV_PIPE_NOTIFY - request notification whenever an asynchronuous s=
ub-
$ !    process created by PIPE completes. Same as SPAWN/NOWAIT/NOTIFY in =
DCL.
$ !    This name is used only for subprocesses running in background (spe=
cified
$ !    with the '&' operator). It is ignored for sequential subprocess
$ !    operations (';' operator) and when using PIPE non-interactively.
$ !
$ DEFINE/SYSTEM/NOLOG ADV_PIPE_NOTIFY 1
$ !
$ !
$ ! 4) ADV_PIPE_DOUBLE_SEMI - controls PIPE's interpretation of the semic=
olon
$ !    (;) character:
$ !
$ !    If this name is *not* defined, a single semicolon is treated as se=
-
$ !    quential operator; when specifying a version number in an RMS file=
 name,
$ !    you must use the dot (.) character instead.
$ !=20
$ !    If this name *is* defined, a single semicolon character is not tre=
ated
$ !    as sequential operator; you'll have to specify 2 semicolons instea=
d (no
$ !    space is allowed beetween them). This allows you use the semicolon=
 in
$ !    RMS file names as usual.
$ !
$ !    Note that a single semicolon is always recognized as sequential op=
erator
$ !    when it is preeceded by one or more blanks or tabs.
$ !
$ !DEFINE/SYSTEM/NOLOG ADV_PIPE_DOUBLE_SEMI 1
$ !
$ !
$ ! 5) ADV_PIPE_DCL_PARSE - if set, PIPE calls DCL to parse every command
$ !    before the subprocess is created and the command is passed to it. =
This
$ !    prevents the user to send unknown commands to piped subprocesses
$ !    which can result in unexpected loops or hangups when the pipe is b=
roken.
$ !    Note that with this feature, the DCL$PATH logical (VMS V6.2 or hig=
her)
$ !    will not work; you must define every foreign command as command sy=
mbol.
$ !
$ !    If you do not use pipes, you can disable this feature.
$ !
$ DEFINE/SYSTEM/NOLOG ADV_PIPE_DCL_PARSE 1
$ !
$ !
$ ! 6) ADV_PIPE_DEBUG - print debugging information. For PIPE's developer=
s
$ !    only. Do not set it unless you want to receive many messages ;-)
$ !
$ !DEFINE/SYSTEM/NOLOG ADV_PIPE_DEBUG 1
$ !
$ exit

=0C---------------------->>> #6: INSTALL.COM <<<----------------------

$ !
$ ! INSTALL File for ADV_PIPE
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D
$ !
$ ! ADV_PIPE V1.1
$ ! -------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ priv =3D "CMKRNL,SYSNAM,SYSPRV"
$ x =3D f$setp(priv)
$ if f$priv(priv)
$ then priv_ok =3D 1
$ else priv_ok =3D 0
$ endi
$ !
$ if f$sear ("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. ""
$ then decc_ok =3D 1
$ else decc_ok =3D 0
$ endi
$ !
$ if f$sear ("SYS$SYSTEM:VAXC.EXE") .nes. ""
$ then vaxc_ok =3D 1
$ else vaxc_ok =3D 0
$ endi
$ !
$ put ""
$ put ""
$ put "                 ADV_PIPE V1.1 Installation procedure"
$ put "                 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"
$ put ""
$ sel =3D p1
$ if sel .nes. "" then goto SELECT
$ put "The following options are available:"
$ put ""
$ put " o) IL: Install the software local only"
$ put ""
$ if priv_ok
$ then
$ put " o) IS: Install the software system-wide"
$ put ""
$ endi
$ if decc_ok .or. vaxc_ok
$ then
$ put " o) CL: Recompile and install the software local only"
$ put ""
$ if priv_ok
$ then
$ put " o) CS: Recompile and install the software system-wide"
$ put ""
$ endi
$ endi
$ put " o) EX: Exit
$ put ""
$ L_1:
$ inqu sel "Please enter your selection"
$ !
$ SELECT:
$ if sel .eqs. "" .or. f$extr(0,1,sel) .eqs. "E"
$ then
$ x =3D f$setp(x)
$ exit
$ endi
$ !
$ if f$leng(sel) .lt. 2 then goto BAD_SEL
$ if f$extr(1,1,sel) .eqs. "S"
$ then
$ if .not. priv_ok then goto BAD_SEL
$ maj =3D f$extr(1,1,f$gets("VERSION"))
$ min =3D f$extr(3,1,f$gets("VERSION"))
$ if (maj .eq. 6 .and. min .ge. 1) .or. maj .gt. 7
$ then
$ put ""
$ put "***WARNING*** - you are installing ADV_PIPE on a system running"
$ put "                VMS V7.1 or higher. On these systems, there is
$ put "                already a DCL built-in PIPE command available."
$ put "                Installing ADV_PIPE will overwrite the command"
$ put "                definition and online help."
$ put ""
$ inqu/nopunc flg "Are you sure that you want to install ADV_PIPE? "
$ ABO_EXIT:
$ if flg .nes. "Y" .and flg .nes. "y"
$ then
$ put ""
$ put "Installation aborted."
$ put ""
$ x =3D f$setp(x)
$ exit
$ endi
$ endi
$ endi
$ !
$ if f$extr(0,1,sel) .eqs. "C"
$ then
$ if .not. (vaxc_ok .or. decc_ok) then goto BAD_SEL
$ gosu COMPILE
$ endi
$ !
$ if f$extr(1,1,sel) .eqs. "L"
$ then
$ gosu CHK_OBJ
$ gosu INST_LOC
$ goto COMMON_END
$ endi
$ !
$ if f$extr(1,1,sel) .eqs. "S"
$ then
$ gosu CHK_OBJ
$ gosu INST_SYS
$ goto COMMON_END
$ endi
$ !
$ BAD_SEL:
$ put ""
$ put "***WARNING*** - Invalid selection - please reenter"
$ put ""
$ sel =3D ""
$ goto L_1
$ !
$ COMMON_END:
$ x =3D f$setp (x)
$ put ""
$ put "ADV_PIPE Installation completed successfully"
$ put ""
$ exit
$ !
$ ! =0C$ !
$ COMPILE:
$ put ""
$ put "Starting compilation pass, please wait..."
$ put ""
$ if decc_ok
$ then
$ put "o - Compiling with DEC C..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then cc/decc/stan=3Dvaxc/nodebu/opti/obje=3Dadv_pipe_vax_d adv_pipe
$ else cc/decc/stan=3Dvaxc/nodebu/opti/obje=3Dadv_pipe_axp adv_pipe
$ endi
$ else
$ put "o - Compiling with VAXC C..."
$ put ""
$ cc/nodebu/opti/obje=3Dadv_pipe_vax_v adv_pipe
$ endi
$ put "Compilation pass completed successfully."
$ retu
$ !
$ ! =0C$ !
$ CHK_OBJ:
$ OK =3D 0
$ if f$gets ("HW_MODEL") .lt. 1024
$ then
$ if decc_ok .and. f$sear ("ADV_PIPE_VAX_D.OBJ") .nes. "" then OK =3D 1
$ if vaxc_ok .and. f$sear ("ADV_PIPE_VAX_V.OBJ") .nes. "" then OK =3D 1
$ else
$ if decc_ok .and. f$sear ("ADV_PIPE_AXP.OBJ") .nes. "" then OK =3D 1
$ endi
$ if OK then retu
$ put ""
$ put "***ERROR***: Cannot create image - required object file is missing=
"
$ put "             You must provide or create the object file before lin=
king."
$ put "             Either recompile the object (by the COMPILE options"
$ put "             provided by this procedure), or copy the object from =
the"
$ put "             distribution kit to this directory."
$ put ""
$ flg =3D "N"
$ goto ABO_EXIT
$ retu
$ !
$ ! =0C$ !
$ INST_LOC:
$ defdir =3D f$trnl ("SYS$LOGIN") - "]" + ".ADV_PIPE]"
$ L_2:
$ put ""
$ put "Please enter directory where the ADV_PIPE files will reside."
$ put "The default is: ''defdir'"
$ put ""
$ inqu insdir "Enter directory name"
$ if insdir .eqs. "" then insdir =3D defdir
$ crea/dire 'insdir'
$ if $status .eq. 1 .or. $status .eqs. "%X10911293" then goto DIR_OK
$ put ""
$ put "***ERROR*** - could not create target directory -"
$ put "              please respecify or use recommended default."
$ insdir =3D ""
$ goto L_2
$ DIR_OK:
$ put ""
$ put "Starting local installation on ''insdir', please wait..."
$ put ""
$ put "o - Linking image..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then
$ if decc_ok
$ then link/notrac/exec=3D'insdir'adv_pipe adv_pipe_vax_d/opti
$ else link/notrac/exec=3D'insdir'adv_pipe adv_pipe_vax_v/opti
$ endi
$ else link/notrac/exec=3D'insdir'adv_pipe/syse adv_pipe_axp/opti
$ endi
$ put "o - Providing product files..."
$ put ""
$ copy adv_pipe.cld,adv_pipe.com,adv_pipe_logs.com 'insdir'
$ put "o - Providing online help library..."
$ put ""
$ libr/help/crea 'insdir'adv_pipe
$ libr/help 'insdir'adv_pipe adv_pipe
$ put "o - Executing startup..."
$ put ""
$ @'insdir'adv_pipe
$ put ""
$ put "Local installation complete."
$ put ""
$ put "You should include the following command in your LOGIN.COM:"
$ put ""
$ put "@''insdir'ADV_PIPE"
$ retu
$ !
$ ! =0C$ !
$ INST_SYS:
$ put ""
$ put "Starting system-wide installation, please wait..."
$ put ""
$ put "o - Linking image..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then=20
$ if decc_ok
$ then link/notrac/exec=3Dsys$common:[sysexe]adv_pipe adv_pipe_vax_d/opti
$ else link/notrac/exec=3Dsys$common:[sysexe]adv_pipe adv_pipe_vax_v/opti
$ endi
$ else link/notrac/exec=3Dsys$common:[sysexe]adv_pipe/syse adv_pipe_axp/o=
pti
$ endi
$ !
$ put "o - Providing startup files..."
$ put ""
$ copy adv_pipe_startup.com sys$common:[sys$startup]
$ copy adv_pipe_systartup.com sys$common:[sysmgr]
$ !
$ put "o - Updating DCLTABLES..."
$ put ""
$ set comm adv_pipe
$ set comm adv_pipe/tabl=3Dsys$share:dcltables/outp=3Dsys$common:[syslib]=
dcltables
$ inst repl/open/head/shar sys$share:dcltables
$ !
$ put "o - Updating online help.."
$ put ""
$ libr/help sys$help:helplib adv_pipe
$ !
$ put "o - Updating startup database..."
$ put ""
$! mc sysman start add file adv_pipe_startup.com/phas=3Dlpmain/mod=3Ddire=
ct
$ !
$ put "o - Executing startup procedure..."
$ put ""
$ @sys$startup:adv_pipe_startup
$ put ""
$ put "System-wide installation complete."
$ retu

=0C---------------------->>> #7: ADV_PIPE.C <<<----------------------

#ifdef VAXC
#module ADV_PIPE "BOL-V1.0/OCT-95"
#else
#pragma module ADV_PIPE "BOL-V1.0/OCT-95"
#endif

/*

ADV_PIPE V1.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

(P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
Municipality of Vienna, Municipal departement 14
A-1010 Wien (Vienna) - AUSTRIA
E-mail: bol@adv.magwien.gv.at

All rights reserved.

*/

#include string
#include stdio
#include stdlib

#include clidef
#include dvidef
#include descrip
#include jpidef
#include lib$routines
#include ssdef
#include starlet

#define SS$_INVARG	0x0FCA
#define INVARG		0x10000000 + SS$_INVARG
#define NOSLOT		0x10000000 + SS$_NOSLOT
#define RMS$_FNF	0x00018292

#define C_BUFSIZ	160
#define C_CLIFLG	CLI$M_NOKEYPAD|CLI$M_NOCONTROL
#define C_NOMSG		0x10000000
#define C_MAXPIPES	8

int   spawn  (char*, int, short, short);
int   xpipe  (char*, short*);
int   getnam (short, char*);
char* getflg (int);
char* semick (char*);
int   chklog (char*);
void  delprc (void);
int   strsub (char*, char*);

char S_syn [] =3D "Syntax error",
     S_err [] =3D "Error opening %s as %s\nRMS Status =3D %08X\n",
     S_spn [] =3D "%%SPAWN-I-INFO, PID =3D %08X, STATUS =3D %08X";

int G_pidarr [C_MAXPIPES], G_curpid, G_semi, G_debug, G_flg =3D C_CLIFLG,=
 G_mode,
    G_parse;

int globalref CTL$AG_CLITABLE;

/***=0C******************************************************************=
*****/

int main ()
{
 char inbuf [C_BUFSIZ], sav_buf [C_BUFSIZ], p_flg =3D 1, q_flg =3D 0, i;

 char *ptr =3D inbuf, *s_ptr =3D sav_buf;

 short len, outmbx;

 int x, stat;

 $DESCRIPTOR (in, inbuf);

 if (!((stat =3D lib$get_foreign (&in, 0, &len)) & 1)) return stat;

 inbuf [len] =3D '\0';

 x =3D lib$getjpi (&JPI$_MODE, 0,0, &G_mode, 0,0);

 if (chklog ("ADV_PIPE_NOSYMBOLS") & 1)  G_flg |=3D CLI$M_NOCLISYM;

 if (chklog ("ADV_PIPE_NOLOGICALS") & 1) G_flg |=3D CLI$M_NOLOGNAM;

 if ((chklog ("ADV_PIPE_NOTIFY") & 1) && G_mode =3D=3D JPI$K_INTERACTIVE)

 G_flg |=3D CLI$M_NOTIFY;

 G_semi =3D chklog ("ADV_PIPE_DOUBLE_SEMI") & 1;

 G_debug =3D chklog ("ADV_PIPE_DEBUG") & 1;

 G_parse =3D chklog ("ADV_PIPE_DCL_PARSE") & 1;

 while (*ptr)
 {
  if (!q_flg)
  {
   if (semick (ptr) !=3D NULL)
   {
    ptr =3D semick (ptr);

    if (p_flg) {puts (S_syn); return INVARG;}

    *s_ptr =3D '\0';

    stat =3D spawn (sav_buf, G_flg, 0,0);

    if (!(stat & 1)) return stat|C_NOMSG;

    s_ptr =3D sav_buf;

    ptr++;

    p_flg =3D 1;
   }
   if (*ptr =3D=3D '&')
   {
    if (p_flg) {puts (S_syn); return INVARG;}

    *s_ptr =3D '\0';

    stat =3D spawn (sav_buf, G_flg|CLI$M_NOWAIT, 0,0);

    if (!(stat & 1)) return stat|C_NOMSG;

    s_ptr =3D sav_buf;

    ptr++;

    p_flg =3D 1;
   }
   if (*ptr =3D=3D '|')
   {
    if (p_flg) {puts (S_syn); return INVARG;}

    *s_ptr =3D '\0';

    while (1)
    {
     stat =3D xpipe (++ptr, &outmbx);

     if (!(stat & 1)) break;

     while (*ptr)
     {
      if (semick (ptr) !=3D NULL) {ptr =3D semick (ptr); break;}

      if (*ptr++ =3D=3D '&')
      {
       puts (S_syn);

       delprc ();

       return INVARG;
      }
     }
     stat =3D spawn (sav_buf, G_flg, 0, outmbx);

     break;
    }
    delprc ();

    if (!(stat & 1)) return stat|C_NOMSG;

    G_curpid =3D 0;

    s_ptr =3D sav_buf;

    if (*ptr) ptr++;

    p_flg =3D 1;
   }
  }
  if (*ptr =3D=3D '"') q_flg =3D ~q_flg;

  if (*ptr =3D=3D '\0') return 1;

  if (!q_flg)
  {
   switch (*ptr)
   {
    case ' ':
    case '\t': {*s_ptr++ =3D *ptr++; break;}

    case ';':
    {
     if (semick (ptr) !=3D NULL) ptr =3D semick (ptr);

     else *s_ptr++ =3D *ptr++;

     break;
    }
    case '&': break;

    default: {p_flg =3D 0; *s_ptr++ =3D *ptr++; break;}
   }  =20
  }
  else {p_flg =3D 0; *s_ptr++ =3D *ptr++;}
 }
 *s_ptr =3D '\0';

 return spawn (sav_buf, G_flg, 0,0)|C_NOMSG;
}

/***=0C******************************************************************=
*****/

int spawn (char *cmd_ptr, int flg, short inmbx, short outmbx)
{
 char inp_buf [128], out_buf [128], ful_buf [128], aux_buf [C_BUFSIZ];

 char *x_ptr, *ptr =3D cmd_ptr, pid_flg =3D 0, q_flg =3D 0, p_flg =3D 1, =
i;

 int x, pid, stat, retstat =3D 1, ctx =3D 0;

 $DESCRIPTOR (cmd, cmd_ptr);
 $DESCRIPTOR (inp, inp_buf);
 $DESCRIPTOR (out, out_buf);
 $DESCRIPTOR (ful, ful_buf);

 inp_buf [0] =3D out_buf [0] =3D '\0';

 if (inmbx)
 {
  if (!((stat =3D getnam (inmbx, inp_buf)) & 1)) return stat;

  inp.dsc$w_length =3D strlen (inp_buf);

  pid_flg =3D 1;
 }
 if (outmbx)
 {
  if (!((stat =3D getnam (outmbx, out_buf)) & 1)) return stat;

  out.dsc$w_length =3D strlen (out_buf);
 }
 while (*ptr)
 {
  if (!q_flg)
  {
   if (*ptr =3D=3D '>')
   {
    if (out_buf [0] || p_flg) {puts (S_syn); return INVARG;}

    *ptr++ =3D '\0';

    x_ptr =3D out_buf;

    while (1)
    {
     if (*ptr =3D=3D ' ' || *ptr =3D=3D '\t') {ptr++; continue;}

     if (*ptr =3D=3D '>') {puts (S_syn); return INVARG;}

     if (*ptr =3D=3D '\0') break;

     if (*ptr =3D=3D '<') break;

     *x_ptr++ =3D *ptr++;
    }
    *x_ptr =3D '\0'; p_flg =3D 0;

    if (!(out.dsc$w_length =3D strlen (out_buf))) {puts (S_syn); return I=
NVARG;}
   }
   if (*ptr =3D=3D '<')
   {
    if (inp_buf [0] || p_flg) {puts (S_syn); return INVARG;}

    *ptr++ =3D '\0';

    x_ptr =3D inp_buf;

    while (1)
    {
     if (*ptr =3D=3D ' ' || *ptr =3D=3D '\t') {ptr++; continue;}

     if (*ptr =3D=3D '<') {puts (S_syn); return INVARG;}

     if (*ptr =3D=3D '\0') break;

     if (*ptr =3D=3D '>') break;

     *x_ptr++ =3D *ptr++;
    }
    *x_ptr =3D '\0'; p_flg =3D 0;

    if (!(inp.dsc$w_length =3D strlen (inp_buf))) {puts (S_syn); return I=
NVARG;}
   }
  }
  if (*ptr !=3D ' ' && *ptr !=3D '\t') p_flg =3D 0;

  if (*ptr =3D=3D '"') q_flg =3D ~q_flg;

  if (*ptr) ptr++;
 }
 if (inp_buf [0] && inp_buf [0] !=3D '_')
 {
  if (!((stat =3D lib$find_file (&inp, &ful, &ctx)) & 1))
  {
   ful_buf [strcspn (ful_buf, " ")] =3D '\0';

   printf (S_err, ful_buf, "input", stat);

   return stat;
  }
  x =3D lib$find_file_end (&ctx);
 }
 ctx =3D 0;

 if (out_buf [0] && out_buf [0] !=3D '_')
 {
  stat =3D lib$find_file (&out, &ful, &ctx);

  if (stat =3D=3D RMS$_FNF) stat =3D 1;

  if (!(stat & 1))
  {
   ful_buf [strcspn (ful_buf, " ")] =3D '\0';

   printf (S_err, ful_buf, "output", stat);

   return stat;
  }
  x =3D lib$find_file_end (&ctx);
 }
 if (pid_flg && G_curpid =3D=3D C_MAXPIPES)
 {
  puts ("Too many pipes - limit to 8");

  return NOSLOT;
 }
 while (*cmd_ptr =3D=3D ' ') cmd_ptr++;

 cmd.dsc$w_length =3D strlen (cmd_ptr);

 if (!(flg & CLI$M_NOWAIT)) flg &=3D ~CLI$M_NOTIFY;

 if (G_debug)
 {
  printf ("$ SPAWN");

  ptr =3D inp_buf; if (*ptr =3D=3D '_') ptr++;

  if (*ptr) printf ("/INPUT=3D%s", ptr);

  ptr =3D out_buf; if (*ptr =3D=3D '_') ptr++;

  if (*ptr) printf ("/OUTPUT=3D%s", ptr);

  if (flg & ~(C_CLIFLG)) printf ("/FLAGS=3D(%s)", getflg (flg));
 }
 x =3D strsub (cmd_ptr, aux_buf);
 =20
 cmd.dsc$a_pointer =3D aux_buf;

 cmd.dsc$w_length =3D strlen (aux_buf);

 if (G_debug) printf (" %s\n", aux_buf);

 if (G_parse)
 {
  if (x) if (!((stat =3D cli$dcl_parse (&cmd, CTL$AG_CLITABLE)) & 1)) ret=
urn stat;
 }
 stat =3D lib$spawn (&cmd, inp_buf [0] ? &inp : 0, out_buf [0] ? &out : 0=
,
		   &flg, 0, &pid, &retstat);
 if (!(stat & 1))
 {
  delprc ();

  return stat;
 }
 if (G_debug)
 {
  printf (S_spn, pid, retstat);

  if (pid_flg) printf (", CNT =3D %d", G_curpid + 1);

  printf ("\n");
 }
 if (pid_flg) G_pidarr [G_curpid++] =3D pid;

 return retstat;
}

/***=0C******************************************************************=
*****/

int xpipe (char *com, short *retmbx)
{
 char q_flg =3D 0, cmd_buf [C_BUFSIZ], sav_buf [C_BUFSIZ], nam_buf [10];

 char *c_ptr =3D cmd_buf, *s_ptr =3D sav_buf;

 short chan =3D 0;

 int x, stat;

 strcpy (cmd_buf, com);

 while (*c_ptr)
 {
  if (!q_flg)
  {
   if (*c_ptr =3D=3D '&') break;

   if (semick (c_ptr) !=3D NULL) {c_ptr =3D semick (c_ptr); break;}

   if (*c_ptr =3D=3D '|')
   {
    *c_ptr++ =3D '\0';

    stat =3D xpipe (c_ptr, &chan);

    if (!(stat & 1)) return stat;

    break;
   }
  }
  if (*c_ptr =3D=3D '"') q_flg =3D ~q_flg;

  *s_ptr++ =3D *c_ptr++;
 }
 *s_ptr =3D '\0';

 if (!strlen (sav_buf)) {puts (S_syn); return INVARG;}

 if (!((stat =3D sys$crembx (0, retmbx, 0,0, 0xFF0F, 0,0,0)) & 1)) return=
 stat;

 if (G_debug)
 {=20
  x =3D getnam (*retmbx, nam_buf);

  printf ("$ CREATE/MAILBOX %s\n", &nam_buf [1]);
 }
 return spawn (sav_buf, (G_flg|CLI$M_NOWAIT) & ~CLI$M_NOTIFY, *retmbx, ch=
an);
}

/***=0C******************************************************************=
*****/

int getnam (short chan, char* retbuf)
{
 short len;

 int stat;

 $DESCRIPTOR (dscr, retbuf);

 dscr.dsc$w_length =3D 10;

 stat =3D lib$getdvi (&DVI$_DEVNAM, &chan, 0,0, &dscr, &len);

 retbuf [len] =3D '\0';

 return stat;
}

/***=0C******************************************************************=
*****/

char *getflg (int flg)
{
 static char retbuf [40];

 retbuf [0] =3D '\0';

 if (flg & CLI$M_NOWAIT) strcat (retbuf, "NOWAIT,");

 if (flg & CLI$M_NOCLISYM) strcat (retbuf, "NOSYMBOLS,");

 if (flg & CLI$M_NOLOGNAM) strcat (retbuf, "NOLOGICALS,");

 if (flg & CLI$M_NOTIFY) strcat (retbuf, "NOTIFY,");

 if (retbuf [0]) retbuf [strlen (retbuf) - 1] =3D '\0';

 return retbuf;
}

/***=0C******************************************************************=
*****/

char* semick (char *ptr)
{
 char *p;

 if (!G_semi)
 {
  if (*ptr =3D=3D ';') return ptr;

  else return NULL;
 }
 if (*ptr !=3D ';') return NULL;

 p =3D ptr - 1;

 if (*p =3D=3D ' ' || *p =3D=3D '\t')
 {
  p =3D ptr + 1;

  if (*p =3D=3D ';') ptr++;

  return ptr;
 }
 ptr++;

 if (*ptr !=3D ';') return NULL;

 else return ptr;
}

/***=0C******************************************************************=
*****/

int chklog (char* nambuf)
{
 char retbuf [8];

 int stat;

 $DESCRIPTOR (nam, nambuf);
 $DESCRIPTOR (ret, retbuf);

 nam.dsc$w_length =3D strlen (nambuf);

 stat =3D lib$sys_trnlog (&nam, NULL, &ret);

 if (stat !=3D SS$_NORMAL) return 0;

 return retbuf [0] =3D=3D '1';
}

/***=0C******************************************************************=
*****/

void delprc (void)
{
 int i, x;

 for (i =3D 0; i !=3D C_MAXPIPES; i++)
 {
  if (G_pidarr [i]) x =3D sys$delprc (&G_pidarr [i], 0);

  G_pidarr [i] =3D 0;
 }
}

/***=0C******************************************************************=
*****/

int strsub (char* in_buf, char* out_buf)
{
 char symnam [16], symval [64], *i_ptr, *o_ptr;

 short len;

 int stat;

 $DESCRIPTOR (nam, symnam);
 $DESCRIPTOR (val, symval);

 i_ptr =3D in_buf; o_ptr =3D symnam;

 while (*i_ptr)
 {
  if (*i_ptr =3D=3D ' ' || *i_ptr =3D=3D '\t' || *i_ptr =3D=3D '/') break=
;

  *o_ptr++ =3D *i_ptr++;
 }
 *o_ptr =3D '\0';

 nam.dsc$w_length=3D strlen (symnam);

 stat =3D lib$get_symbol (&nam, &val, &len);

 if (!(stat & 1)) strcpy (out_buf, in_buf);

 else
 {
  symval [len] =3D '\0';

  strcpy (out_buf, symval);

  strcat (out_buf, i_ptr);
 }
 if (out_buf [0] =3D=3D '$')
 {
  strcpy (symval, "MCR ");

  strcat (symval, &out_buf [1]);

  strcpy (out_buf, symval);
 }
 if (out_buf [0] =3D=3D 'm') out_buf [0] =3D 'M';

 if (out_buf [1] =3D=3D 'c') out_buf [1] =3D 'C';

 if (out_buf [0] =3D=3D 'M' && out_buf [1] =3D=3D 'C') return 0;

 else return 1;
}

=0C---------------------->>> #8: ADV_PIPE.HLP <<<----------------------

!
! ADV_PIPE V1.1
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
1 PIPE

  Pipe is a tool that allows you issuing DCL commands with U*X shell
  separation and redirection operators. You can specify more than one
  DCL command in a command line, and for every command, you can control
  where the output of the command is sent or received.

  PIPE provides its functions by creating (SPAWNing) subprocesses.
  Therefore, you must be able to create subprocesses (your subprocess
  quota must be large enough). In addition, TMPMBX privilege is required.

  See the subtopics for more information.

2 Author

  PIPE was written by Ing. Ferry Bolhar, MD-ADV/MA, Vienna, Austria.
  Please send any suggestions to: bol@adv.magwien.gv.at.

2 Invokation

  PIPE is invoked with the 'P' command. Following this command, you
  specify your DCL commands, separators and redirectors. The syntax
  is:

  $ P <cmd> [<red>] [<sep>] [<cmd> [<red>] [<sep>]...]

  where:

  <cmd> is a valid DCL command or a symbol containing a command.
=20
  <red> is one or more of PIPE's redirectors (see topic "Redirectors"
        for more information).

  <sep> is one of PIPE's command separators (see topic "Separators").

  Blanks beetween DCL commands, separators and redirectors are
  optional.

  When using in DCL procedures, you can force the execution of PIPE
  in a command line by specifying two dollars signs instead of one
  at the beginning of the line.

2 Logical_Names

  There are six logical names which you can use to control some
  of PIPE's behaviour. All names may be defined in any logical name
  table (PROCESS, JOB, GROUP, SYSTEM). If the equivalence string of
  a name is "1", its function is enabled, any other value explicitly
  disables the function. In addition, if the name does not exist,
  the function is disabled.

  All names are described in the following topics.

3 ADV_PIPE_NOSYMBOLS

  When set, DCL symbols are not copied to the subprocess (similar
  to SPAWN/NOSYMBOLS). When cleared, symbols are copied. Note that
  defining this name can improve process creation. Note in addition,
  that, since symbol substitution in the command line occurs in the
  parent process, there is usually no need to pass DCL symbols to
  PIPE's subprocesses.
 =20
3 ADV_PIPE_NOLOGICALS

  When set, per-process logical names are not copied to the subprocess
  (similar to SPAWN/NOLOGICALS). When cleared, they are copied. Note
  that defining this name can improve process creation.

  If the subprocess must access logical names within your job, you
  should place the logicals into the job-wide name table (DEFINE/JOB).

3 ADV_PIPE_NOTIFY

  When set, a notification message is displayed if a process started
  in background completes (similar to SPAWN/NOTIFY). This name is used
  only for background jobs (&). In addition, it is ignored when using
  PIPE non-interactively.

3 ADV_PIPE_DOUBLE_SEMI

  This name controls PIPE's interpretation of the semicolon (;):

  If set, a single semicolon character is not treated as separator;
  you'll have to specify 2 semicolons instead (no space is allowed
  beetween them). This allows you use the semicolon in RMS file names
  as usual.

  If not set, a single semicolon is treated as sequential operator;
  when specifying a version number in an RMS file name, you must use
  the dot (.) character instead.

  Note that a single semicolon is always recognized as separator
  when it is preeceded by one or more blanks or tabs.

3 ADV_PIPE_DCL_PARSE

  If set, PIPE calls DCL to parse every command before a subprocess
  is created and the command string is passed to it. If not set, the
  commands are passed without checks.

  Note that, in a pipe, if DCL rejects a command, the executing
  subprocess dies and the pipe is broken. This can cause PIPE to hang.

3 ADV_PIPE_DEBUG

  If set, PIPE displays debugging information. If cleared, this
  information is not displayed. For PIPE's developers only, should
  not set normally.

2 Redirectors

  Redirectors are used to change a programs input (SYS$INPUT, stdin)
  and output (SYS$OUTPUT, stdout) device. PIPE supports these
  redirectors:

  < name...Input of the preceeding command is taken from 'name'. This
           may be a file, terminal, mailbox or any other device capable
           of sending data.

  > name...Output of the preceeding command is sent to 'name'. This
           may be a file, terminal, mailbox or any other device capable
           of receiving data. This affects both output channels, stdout
	   (SYS$OUTPUT) and stderr (SYS$ERROR).

  The space beetween the redirector and 'name' is optional.

  If you specify a redirector and a command separator, the redirector
  must be specified first.

  Note that redirectors are not allowed if the input/output of a program
  is piped to another program.

3 Example

  $ P RUN TEST > X.X

  The output generated by the program TEST is written into file X.X.


2 Restrictions

  o) The entire command line may not exceed 132 characters.

  o) When starting subprocesses in background (&), they are deleted
     when the parent process dies. This is the behaviour of OpenVMS,
     there is no way to change it.

  o) There is a maximum of 8 pipes in a single command line.

  o) Implementing Pipes is done with mailboxes. The creation of
     mailboxes requires non-paged pool and may be limited by your
     pooled byte quota (BYTLM). In addition, TMPMBX privilege is
     required.

  o) When piping or starting subprocesses in background, you must have
     sufficient subprocess quota (PRCLM).

  o) You cannot start pipes in background, a piped command group
     must not be terminated with &.

  o) The logical name DCL$PATH (VMS V6.2 or higher) is not supported
     in PIPE's command line. You must define every foreign command as
     DCL symbol prior to use it in a command line.

2 Separators

  Command Operators (also called "Separators") are used to separate
  DCL commands in a command line. PIPE supports these separators:

  cmd1 ; cmd2... Sequential execution. Start of 'cmd2' begins when
                 'cmd1' completes.

                 Depending on the logical name ADV_PIPE_DOUBLE_SEMI,
                 PIPE recognizes either one or two semicolons as
                 separator. This allows you to use the single semi-
                 colon als version number delimiter in RMS file names.

  cmd1 & cmd2....Concurrent (background) execution. 'cmd2' is started
                 immediately after 'cmd1'. 'cmd1' is executed in
                 background, asynchronuous to 'cmd2'.

  cmd1 | cmd2....Piped commands. Output of 'cmd1' is taken as input
                 for 'cmd2'. You can build a command chain with up
                 to eight pipes.

3 Examples

  $ P RUN TEST & DIR > Z.Z ; SHOW LOGICAL A

  TEST is started and is placed in background for execution. Next,
  the DIR command is executed and its output is written to Z.Z.
  Finally, after execution of DIR, the SHOW LOGICAL command runs.

  $ P SHOW SYSTEM | SEARCH SYS$INPUT UCX > UCX.LOG

  The output of SHOW SYSTEM is sent to the SEARCH command which looks
  for the string 'UCX' and writes all lines containing this string to
  the file UCX.LOG. Note that you must tell SEARCH to read its data
  from stdin by specifying SYS$INPUT as file parameter.

=0C---------------------->>> #9: ADV_PIPE.CLD <<<----------------------

!
! ADV_PIPE V1.1
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
define verb $ image pipe_dir:adv_pipe
synonym P=20
synonym PIPE
parameter p1, prompt =3D "Command(s)", value (required, type =3D $rest_of=
_line)

=0C---------------------->>> #10: ADV_PIPE_AXP.OPT <<<-------------------=
---

! ADV_PIPE V1.1
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_pipe_axp
stack=3D16

=0C---------------------->>> #11: ADV_PIPE_VAX_D.OPT <<<-----------------=
-----

! ADV_PIPE V1.1
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_pipe_vax_d
sys$system:sys.stb/sele
stack=3D16

=0C---------------------->>> #12: ADV_PIPE_VAX_V.OPT <<<-----------------=
-----

! ADV_PIPE V1.1
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_pipe_vax_v
sys$share:vaxcrtl/shar
sys$system:sys.stb/sele
stack=3D16

----------------------->>> END OF MAIL <<<----------------------


--------------15FB59E21CFB
Content-Type: text/plain; charset=iso-8859-1; name="adv_runusr010.mai"
Content-Disposition: inline; filename="adv_runusr010.mai"
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by marmeladinger.adv.magwien.gv.at id MAA01422


	ADV_RUNUSR V1.0
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	This mail contains the following files (in this order):

	$$$README.DOC		General information about ADV_RUNUSR. As
				its name indicates, read this file before
				installing ADV_RUNUSR. Please ignore the
				information concerning saveset processing.

	ADV_RUNUSR.COM		Login command procedure.

	ADV_PIPE_STARTUP.COM	System startup procedure.

	INSTALL.COM		Installation procedure for ADV_RUNUSR.

	ADV_RUNUSR.C		The C source.

	ADV_RUNUSR_MSG.MSG	Message definitions.

	ADV_RUNUSR_Vx.HLP	Online help file for VMS V5, V6 and V7.

	ADV_RUNUSR_Vx.CLD	Command definitions for VMS V5, V6 and V7.

	ADV_RUNUSR_SETNAM.MAR	Macro routine to change username.

	ADV_RUNUSR_AXP.OPT	Linker option file for Alpha.

	ADV_RUNUSR_VAX_D.OPT	Linker option file for VAX with DEC C

	ADV_RUNUSR_VAX_V.OPT	Linker option file for VAX with VAX C

	(Total of 16 files.)


	You need a VAX C or DEC C compiler to build ADV_RUNUSR.

	All files are separated with a header line containing a
	form feed (ASCII 12) character.

	After extracting all files from this mail in a directory
	go to this directory and type @INSTALL.


	Hope you'll find it useful. Have fun with ADV_RUNUSR!

					Greetings, Ferry

=0C---------------------->>> #1: $$$README.DOC <<<----------------------


	ADV_RUNUSR V1.0
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	ADV_RUNUSR provides the following enhancements to the DCL
	RUN command:

	o - a /USER qualifier, allowing you to specify a username
	    for the new process, as well as an UIC;

	o - a /[NO]IDENTIFY qualifier to suppress the RUN-S-PROC_ID
	    message;

	o - the DCL symbol $RUN_PID which is contains the PID of
	    the last created process;

	o - privilege names may now be abbreviated to a single
	    character as long as they remain unambiguous.

	ADV_RUNUSR consists of the single image SYS$SYSTEM:
	ADV_RUNUSE.EXE which replaces the DEC-supplied RUNDET.EXE.



	1) Installation Requirements
	----------------------------

	ADV_RUNUSR requires VAX/VMS V5.4 or higher or OpenVMS AXP V1.5
	or higher. No additional software is required for installation
	and use. The following resources are required:

	User-local installation:

	Resource		VAX	Alpha
	-------------------------------------
	Blocks in [.ADV_RUNUSR]  90       106



	System-wide installation:

	Resource		VAX	Alpha
	-------------------------------------
	Blocks on system disk    22	   36



	2) Installation
	---------------

	To install ADV_RUNUSR:

	o) Create a temporary directory (CREATE/DIRECTORY [.TMP]).
=09
	o) Copy the product saveset into this directory and place yourself
	   therein (SET DEFAULT).

	o) Extract the backup savset:

	   $ BACKUP ADV_RUNUSR010.SAV/SAVE []

	o) Call the installation procedure.

	   $ @INSTALL

	The installation procedure offers a menu with the following
	selections:

	1) Install the software local only
	2) Recompile & install the software local only
	3) Install the software system-wide
	4) Recompile & install the software system-wide

	The first and second choice perform a user-local installation.
	No privileges are required for this type of installation. You
	must specify a directory wherein the [.ADV_RUNUSR] subdirectory=20
	is created. All product files are placed in this directory.

	A system-wide installation makes the product available on the
	entire system (or VMScluster) which requires, of course, privi-
	leges (SYSPRV, SYSNAM and CMKRNL). You must have these privileges,
	otherwise the installation procedure doesn't display these
	options. A system-wide installation copies all required files
	to the approbiate system directories and updates the CLI tables,
	system startup database and online-help library.

	When you have changes made on the sources, you must recompile
	the program. Otherwise, it is sufficient when you link it. Note
	that you need a C compiler (DEC C or VAX C) to recompile the
	sources. If the installation procedure determines that you have
	no C compiler installed, the choices for recompilation are not
	displayed.

	After selecting the desired installation option, the procedure
	starts. When the message

	"Installation completed successfully"

	is displayed, the installation has completed. You may now
	delete the contents of the temporary directory holding the
	extracted saveset files.



	3) Startup
	----------

	User-local:

	For user-local installation, a file named ADV_RUNUSR.COM is
	created in the [.ADV_RUNUSR] subdirectory during installation.
	This procedure should run as part of your login. It loads
	the updated RUN command verb from the CLI definition file
	ADV_RUNUSR.CLD and updates the logical SYS$HELP in your job
	table to point to SYS$HELP as well as to the help library
	[.ADV_RUNUSR]ADV_RUNUSR.HLB which contains help about the
	modified RUN command.


	System-wide:

	ADV_RUNUSR is started automatically during the installation.
	The startup procedure is inserted into the system startup
	database (phase =3D LPMAIN, mode =3D DIRECT). For a manual start,
	enter:

	$ @SYS$STARTUP:ADV_RUNUSR_STARTUP

	You must execute this command on every cluster member in a
	VMScluster.

	You need SYSPRV and CMKRNL privileges to run the startup
	procedure.



	4) Usage
	--------

	ADV_RUNUSR adds the following features to the DCL RUN
	command (which is used to create detached processes or
	subprocesses).


	a) /USER Qualifier
	------------------

	The /USER qualifier allows you to specify a 1 to 12
	character username which the created process should run
	under. Like /UIC, it forces the creation of a detached
	process; DETACH and CMKRNL privileges are required.

	If you specify /USER with /AUTHORIZE, the target
	process' UIC is taken from the user authorization
	file (UAF) which requires read access to the UAF in
	addition to the above privileges. In this case, the
	username supplied with /USER must exist in the UAF.
	You may overwrite the default UIC from the UAF with
	the /UIC qualifier.

	If you specify /NOAUTHORIZE, the default UIC is taken
	from your process. In this case, you may specify even
	non-existant usernames with /USER. To supply a UIC
	different from your own, use the /UIC qualifier.

	The following table shows all qualifiers which creates
	detached processes or are meaningful for detached
	processes only:

	Qualifier		Required Privileges:
	----------------------------------------------------
	/AUTHORIZE		DETACH
	/JOB_TABLE_QUOTA	-
	/ON			-			1)
	/TRUSTED		DETACH			1)
	/UIC			DETACH
	/USER			DETACH,CMKRNL

	1) VMS V7 and higher only



	b) /[NO]IDENTIFY
	----------------

	The /IDENTIFY qualifier, when used in the negated form
	(/NOIDENTIFY) suppress the message displayed by the RUN
	command whenever a process was created successfully:

	%RUN-S-PROC_ID, identification of created process is XXXXXXXX

	This may be useful in interactive DCL procedures when
	forms or escape sequences are used to display data on
	the screen, and these messages otherwise would destroy
	the screen.

	This qualifier is meaningful in its negated form only.



	c) DCL Symbol $RUN_PID
	----------------------

	Whenever a detached process or subprocess was created,
	the global DCL symbol $RUN_PID is updated with the PID of
	the created process (this is similar to the $ENTRY symbol
	provided by the SUBMIT and PRINT commands). You may use
	this symbol in your DCL procedures to further control the
	process or obtain information about it. Together with
	/NOIDENTIFY, you can create and control processes without
	displaying their PID's.



	d) Changed behaviour in privilege name abbreviation
	---------------------------------------------------

	The DEC-supplied RUN command requires all privilege
	names spelled out at least to 3 characters, even if
	one character would be sufficient for unambiguity
	(i.e., "W" for "WORLD"), otherwise, the following
	message is displayed:

	$ RUN/DET/PRIV=3DW TEST
	%RUN-F-INVQUAVAL, value 'W' invalid for /PRIVILEGES qualifier
	$

	ADV_RUNUSR removes this restriction. You may now
	abbreviate privileges names to a single character,
	as long as they remain unambiguous.

	Note, however, that Digital recommends to full spell
	out privileges names, since abbreviations currently
	unambiguous may become ambiguous in future VMS versions
	when new privileges are added.
=09


	5) File created by the installation
	-----------------------------------

	Local-only:

	[.ADV_RUNUSR]ADV_RUNUSR.EXE		RUNUSR Image

	[.ADV_RUNUSR]ADV_RUNUSR.CLD		Command definition

	[.ADV_RUNUSR]ADV_RUNUSR.HLB		Help library

	[.ADV_RUNUSR]ADV_RUNUSR.COM		Local startup (login) procedure



	System-wide:

	SYS$SYSTEM:ADV_RUNUSR.EXE		RUNUSR Image.

	SYS$STARTUP:ADV_RUNUSR_STARTUP.COM	Startup procedure.



	6) Copyright note
	-----------------

        This software is COPYRIGHT =A9 1993-1995, Municipality of
        City of Vienna. ALL RIGHTS RESERVED.

        Permission is granted for non-profit redistribution and use,
        provided that no changes are made in the sources and that
        this copyright notice remains intact.

        This software is provided "AS IS". The author, Ing. Ferry
        Bolh=E1r (bol@adv.magwien.gv.at) makes no representations or
        warranties with respect to this software.

	Please send any suggestions to the author, they are very
	appreciated.

=0C---------------------->>> #2: ADV_RUNUSR.COM <<<----------------------

$ !
$ ! Login procedure for ADV_RUNUSR
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! ADV_RUNUSR V1.0
$ ! ---------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! This file is used to make the modified RUN command and new
$ ! online help known to the current process.
$ !
$ x =3D f$veri(0)
$ z =3D f$envi("PROCEDURE")
$ devdir =3D f$pars(z,,,"DEVICE") + f$pars(z,,,"DIRECTORY")
$ defi/job/nolog runusr_dir 'devdir'
$ set comm runusr_dir:adv_runusr
$ hlp =3D f$trnl("HLP$LIBRARY")
$ if hlp .eqs. ""
$ then
$ defi/job hlp$library runusr_dir:adv_runusr
$ else
$ n =3D 1
$ L_1:
$ hlp =3D f$trnl("HLP$LIBRARY_''n'")
$ if hlp .nes. ""
$ then
$ n =3D n + 1
$ goto L_1
$ endi
$ defi/job/nolog hlp$library_'n' runusr_dir:adv_runusr
$ endi
$ x =3D f$veri(x)
$ exit

=0C---------------------->>> #3: ADV_RUNUSR_STARTUP.COM <<<--------------=
--------

$ !
$ ! ADV_RUNUSR_STARTUP.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! RUNUSR Version V1.0
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ ! Revision history:
$ !
$ ! 20-OCT-1996 BOL     V1.0 created.
$ !
$ prod_vers =3D "010"
$ !
$ i_v =3D "V1.0"
$ put =3D "writ sys$output"
$ sysdef =3D "defi/syst/exec/nolog"
$ on warn then goto ERROR_EXIT
$ !
$ put "%RUNUSR-I-START_BEG, startup for ADV_RUNUSR ''i_v' is running, ple=
ase wait..."
$ prvprv =3D f$setp ("SYSPRV,SYSNAM,CMKRNL")
$ if .not. f$priv ("SYSPRV,SYSNAM,CMKRNL") then goto NO_PRIV
$ sysdef ADV_RUNUSR_ISHI 1
$ sysdef RUNUSR_DIR SYS$SYSTEM
$ deas/syst/exec ADV_RUNUSR_ISHI
$ sysdef ADV_RUNUSR_ISDO "''prod_vers'"
$ ERROR_EXIT:
$ if f$trnl ("ADV_RUNUSR_ISDO") .eqs. ""
$ then put "%RUNUSR-E-NOTSTARTED, ADV_RUNUSR ''i_v' was not started!"
$ else put "%RUNUSR-I-START_END, startup for ADV_RUNUSR ''i_v' completed =
successfully"
$ endi
$ x =3D f$setp (prvprv)
$ exit
$ !
$ NO_PRIV:
$ put "%RUNUSR-F-NOPRIV, insufficient privileges for startup"
$ goto ERROR_EXIT

=0C---------------------->>> #4: INSTALL.COM <<<----------------------

$ !
$ ! INSTALL File for ADV_RUNUSR
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D
$ !
$ ! ADV_RUNUSR V1.0
$ ! ---------------
$ !
$ ! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
$ ! Municipality of Vienna, Municipal departement 14
$ ! A-1010 Wien (Vienna) - AUSTRIA
$ ! E-mail: bol@adv.magwien.gv.at
$ !
$ ! All rights reserved.
$ !
$ priv =3D "CMKRNL,SYSNAM,SYSPRV"
$ x =3D f$setp(priv)
$ if f$priv(priv)
$ then priv_ok =3D 1
$ else priv_ok =3D 0
$ endi
$ !
$ if f$sear ("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. ""
$ then decc_ok =3D 1
$ else decc_ok =3D 0
$ endi
$ !
$ if f$sear ("SYS$SYSTEM:VAXC.EXE") .nes. ""
$ then vaxc_ok =3D 1
$ else vaxc_ok =3D 0
$ endi
$ !
$ put ""
$ put ""
$ put "                ADV_RUNUSR V1.1 Installation procedure"
$ put "                =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"
$ put ""
$ sel =3D p1
$ if sel .nes. "" then goto SELECT
$ put "The following options are available:"
$ put ""
$ put " o) IL: Install the software local only"
$ put ""
$ if priv_ok
$ then
$ put " o) IS: Install the software system-wide"
$ put ""
$ endi
$ if decc_ok .or. vaxc_ok
$ then
$ put " o) CL: Recompile and install the software local only"
$ put ""
$ if priv_ok
$ then
$ put " o) CS: Recompile and install the software system-wide"
$ put ""
$ endi
$ endi
$ put " o) EX: Exit
$ put ""
$ L_1:
$ inqu sel "Please enter your selection"
$ !
$ SELECT:
$ if sel .eqs. "" .or. f$extr(0,1,sel) .eqs. "E"
$ then
$ x =3D f$setp(x)
$ exit
$ endi
$ if f$leng(sel) .lt. 2 then goto BAD_SEL
$ !
$ maj =3D f$extr(1,1,f$gets("VERSION"))
$ min =3D f$extr(3,1,f$gets("VERSION"))
$ suff =3D "V5"
$ if maj .ge. 6
$ then
$ if maj .eq. 6 .and. min .ge. 1 then suff =3D "V6"
$ if maj .ge. 7 then suff =3D "V7"
$ endi
$ if f$extr(0,1,sel) .eqs. "C"
$ then
$ if .not. (vaxc_ok .or. decc_ok) then goto BAD_SEL
$ gosu COMPILE
$ endi
$ !
$ if f$extr(1,1,sel) .eqs. "L"
$ then
$ gosu CHK_OBJ
$ gosu INST_LOC
$ goto COMMON_END
$ endi
$ !
$ if f$extr(1,1,sel) .eqs. "S"
$ then
$ gosu CHK_OBJ
$ gosu INST_SYS
$ goto COMMON_END
$ endi
$ !
$ BAD_SEL:
$ put ""
$ put "***WARNING*** - Invalid selection - please reenter"
$ put ""
$ sel =3D ""
$ goto L_1
$ !
$ COMMON_END:
$ x =3D f$setp (x)
$ put ""
$ put "ADV_RUNUSR Installation completed successfully"
$ put ""
$ exit
$ !
$ ! =0C$ !
$ COMPILE:
$ put ""
$ put "Starting compilation pass, please wait..."
$ put ""
$ if suff .eqs. "V6" then defstr =3D "/defi=3DVMS_V6"
$ if suff .eqs. "V7" then defstr =3D "/defi=3DVMS_V7"
$ if decc_ok
$ then
$ put "o - Compiling with DEC C..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then cc/decc/stan=3Dvaxc/nodebu/noopti'defstr'/obje=3Dadv_runusr_vax_d_=
'suff' adv_runusr
$ else cc/decc/stan=3Dvaxc/nodebu/noopti'defstr'/obje=3Dadv_runusr_axp_'s=
uff' adv_runusr
$ endi
$ else
$ put "o - Compiling with VAXC C..."
$ put ""
$ cc/nodebu/noopti'defstr'/obje=3Dadv_runusr_vax_v_'suff' adv_runusr
$ endi
$ put "Compilation pass completed successfully."
$ retu
$ !
$ ! =0C$ !
$ CHK_OBJ:
$ OK =3D 0
$ if f$gets ("HW_MODEL") .lt. 1024
$ then=20
$ fil =3D "ADV_RUNUSR_VAX_V_''suff'.OBJ"
$ if vaxc_ok .and. f$sear (fil) .nes. "" then OK =3D 1
$ fil =3D "ADV_RUNUSR_VAX_D_''suff'.OBJ"
$ if decc_ok .and. f$sear (fil) .nes. "" then OK =3D 1
$ fil =3D "ADV_RUNUSR_SETNAM_VAX.OBJ"
$ if f$sear (fil) .eqs. "" then -
$ macr/nodebu/obje=3D'fil' adv_runusr_setnam
$ fil =3D "ADV_RUNUSR_MSGPTR_VAX.OBJ"
$ if f$sear (fil) .eqs. "" then -
$ mess/symb/notext/obje=3D'fil' adv_runusr_msg/file=3DCLIUTLMSG
$ else
$ fil =3D "ADV_RUNUSR_AXP_''suff'.OBJ"
$ if decc_ok .and. f$sear (fil) .nes. "" then OK =3D 1
$ fil =3D "ADV_RUNUSR_SETNAM_AXP.OBJ"
$ if f$sear (fil) .eqs. "" then -
$ macr/nodebu/obje=3D'fil' adv_runusr_setnam
$ fil =3D "ADV_RUNUSR_MSGPTR_AXP.OBJ"
$ if f$sear (fil) .eqs. "" then -
$ mess/symb/notext/obje=3D'fil' adv_runusr_msg/file=3DCLIUTLMSG
$ endi
$ if OK then retu
$ put ""
$ put "***ERROR***: Cannot create image - required object file is missing=
"
$ put "             Filename: ''fil'."
$ put "             You must provide or create this file before linking."
$ put "             Either recompile the object (by the COMPILE options"
$ put "             provided by this procedure), or copy the object from"
$ put "             the distribution kit to this directory."
$ put ""
$ put ""
$ put "Installation aborted."
$ put ""
$ x =3D f$setp(x)
$ exit
$ retu
$ !
$ ! =0C$ !
$ INST_LOC:
$ defdir =3D f$trnl ("SYS$LOGIN") - "]" + ".ADV_RUNUSR]"
$ L_2:
$ put ""
$ put "Please enter directory where the ADV_RUNUSR files will reside."
$ put "The default is: ''defdir'"
$ put ""
$ inqu insdir "Enter directory name"
$ if insdir .eqs. "" then insdir =3D defdir
$ crea/dire 'insdir'
$ if $status .eq. 1 .or. $status .eqs. "%X10911293" then goto DIR_OK
$ put ""
$ put "***ERROR*** - could not create target directory -"
$ put "              please respecify or use recommended default."
$ insdir =3D ""
$ goto L_2
$ DIR_OK:
$ put ""
$ put "Starting local installation on ''insdir', please wait..."
$ put ""
$ put "o - Linking image..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then
$ if decc_ok
$ then
$ copy adv_runusr_vax_d_'suff'.obj adv_runusr_vax_d.obj
$ link/notrac/exec=3D'insdir'adv_runusr adv_runusr_vax_d/opti
$ dele adv_runusr_vax_d.obj.
$ else=20
$ copy adv_runusr_vax_v_'suff'.obj adv_runusr_vax_v.obj
$ link/notrac/exec=3D'insdir'adv_runusr adv_runusr_vax_v/opti
$ dele adv_runusr_vax_v.obj.
$ endi
$ else
$ copy adv_runusr_axp_'suff'.obj adv_runusr_axp.obj
$ link/notrac/exec=3D'insdir'adv_runusr/syse adv_runusr_axp/opti
$ dele adv_runusr_axp.obj.
$ endi
$ put "o - Providing product files..."
$ put ""
$ copy adv_runusr_'suff'.cld 'insdir'adv_runusr.cld
$ copy adv_runusr.com 'insdir'
$ put "o - Providing online help library..."
$ put ""
$ libr/help/crea 'insdir'ADV_RUNUSR
$ libr/help 'insdir'adv_runusr adv_runusr_'suff'
$ put "o - Executing startup..."
$ put ""
$ @'insdir'ADV_RUNUSR
$ put ""
$ put "Local installation complete."
$ put ""
$ put "You should include the following command in your LOGIN.COM:"
$ put ""
$ put "@''insdir'ADV_RUNUSR"
$ retu
$ !
$ ! =0C$ !
$ INST_SYS:
$ put ""
$ put "Starting system-wide installation, please wait..."
$ put ""
$ put "o - Linking image..."
$ put ""
$ if f$gets ("HW_MODEL") .lt. 1024
$ then=20
$ if decc_ok
$ then=20
$ copy adv_runusr_vax_d_'suff'.obj adv_runusr_vax_d.obj
$ link/notrac/exec=3Dsys$common:[sysexe]adv_runusr adv_runusr_vax_d/opti
$ dele adv_runusr_vax_d.obj.
$ else=20
$ copy adv_runusr_vax_v_'suff'.obj adv_runusr_vax_v.obj
$ link/notrac/exec=3Dsys$common:[sysexe]adv_runusr adv_runusr_vax_v/opti
$ endi
$ else=20
$ copy adv_runusr_axp_'suff'.obj adv_runusr_axp.obj
$ link/notrac/exec=3Dsys$common:[sysexe]adv_runusr/syse adv_runusr_axp/op=
ti
$ dele adv_runusr_axp.obj.
$ endi
$ !
$ put "o - Providing startup files..."
$ put ""
$ copy adv_runusr_startup.com sys$common:[sys$startup]
$ !
$ put "o - Updating DCLTABLES..."
$ put ""
$ set comm adv_runusr_'suff'
$ set comm adv_runusr_'suff'/tabl=3Dsys$share:dcltables/outp=3Dsys$common=
:[syslib]dcltables
$ inst repl/open/head/shar sys$share:dcltables
$ !
$ put "o - Updating online help.."
$ put ""
$ libr/help sys$help:helplib adv_runusr_'suff'
$ !
$ put "o - Updating startup database..."
$ put ""
$ mc sysman start add file adv_runusr_startup.com/phas=3Dlpmain/mod=3Ddir=
ect
$ !
$ put "o - Executing startup procedure..."
$ put ""
$ @sys$startup:adv_runusr_startup
$ !
$ put "System-wide installation complete."
$ retu

=0C---------------------->>> #5: ADV_RUNUSR.C <<<----------------------

#ifdef VAXC
#module RUNUSR "BOL-V1.0/AUG-96"
#else
#pragma module RUNUSR "BOL-V1.0/AUG-96"
#endif

#ifdef __DECC			/* Not available in VAXCDEF */
#include cli$routines		/* CLI$xxx() routine definitions */
#endif
#include climsgdef		/* CLI$_xxx status codes */
#include descrip		/* Descriptor definitions */
#include lib$routines		/* LIB$xxx() routine definitions */
#include libclidef		/* LIB$xxx CLI-specific symbols */
#include libdef			/* LIB$_xxx status codes */
#include jpidef			/* JPI$_xxx item codes */
#include pqldef			/* PQL$_xxx quota codes */
#include prcdef			.* PRC$M_xxx create process flags */
#include prvdef			/* PRV$_xxx privilege bit definitions */
#include rmsdef			/* RMS$_xxx status codes */
#include ssdef			/* SS$_xxx status codes */
#include starlet		/* SYS$xxx() system service definitions */
#include stdio			/* standard I/O functions */
#include string			/* strxxx() string routine definitions */

#define NOMSG	0x10000000;	/* DCL shouldn't print the error message */

/* Define literals for message codes. */

#define RUN$_PARSEFAIL 0x00C0124C
#define RUN$_INVQUAVAL 0x00C0132C

/* Define privilege bit values (not define in STARLET) */

#define PRV$M_UPGRADE	0x01
#define PRV$M_DOWNGRADE 0x02
#define PRV$M_GRPPRV    0x04
#define PRV$M_READALL   0x08
#define PRV$M_IMPORT    0x10
#define PRV$M_AUDIT     0x20
#define PRV$M_SECURITY  0x40

/* If VMS_V7 is defined, define VMS_V6 as well. */

#ifdef VMS_V7
#define VMS_V6 1
#endif

int globalvalue

RUN$_PROC_ID,RUN$_SCHDWK,RUN$_CREPRC,RUN$_GETJPI,
RUN$_CVTERR,RUN$_INVUIC,RUN$_ILLVAL;

extern int _setnam();

/* Define item list structure for SYS$GETJPI. */

struct itmlst
{
 short size;            /* Item size */
 short code;            /* Item code */
 int*  info;            /* Item information */
 void* len;             /* Item length (or unused) */
};

/* Define quota list structure. */

#ifdef __DECC		/* Ensure that no alignment occurs here. */
#pragma nomember_alignment
#endif

struct quolst
{
 char code;		/* Quota code; */
 int  val;		/* Value */
} RUN_QUOTA[16],	/* 16 entries should be enough */
*RUN_QUOLIST;		/* Pointer to quota list. */

#ifdef __DECC		/* Restore alignment. */
#pragma member_alignment
#endif

/* Local routines. */

void
get_prcinf(),		/* Get info about our process */
get_cmdlin(),		/* Get parameters and qualifiers */
 get_imgnam(),		/* Obtain and parse image name */
 get_string(),		/* Get string value */
 chk_flg(),		/* Check for process creation flags */
 get_usrnam(),		/* Get and check username */
 get_uic(),		/* Get and validate UIC string */
 get_value(),		/* Get numeric value */
 get_quotas(),		/* Get process quotas */
 get_privs(),		/* Get privileges */
 get_times(),		/* Get schedule, delay and interval times */
creprc();		/* Create the process */

int get_prvval();	/* Get privilege mask value */

/* Global data. */

char
OUR_USRNAM[16],		/* Our username */
RUN_USRNAM[16],		/* Specified username */
RUN_PRCNAM[16],		/* Specified process name */
RUN_INPUT[256],		/* SYS$INPUT */
RUN_OUTPUT[256],	/* SYS$OUTPUT */
RUN_ERROR[256],		/* SYS$ERROR */
RUN_IMAGE[256],		/* Specified image name */
RUN_NODNAM[6],		/* Node name (VMS V7 and higher only) */
FUL_IMAGE[256];		/* Resultant image name */

int
RUN_PID,		/* Returned PID */
RUN_UIC,		/* Specified UIC */
RUN_PRIORITY,		/* Specified priority */
RUN_MBXUNIT,		/* Termination maibox unit no. */
RUN_PRIVS[2],		/* Specified or inherited privileges */
OUR_PRIVS[2],		/* Our privileges */
RUN_FLAGS,		/* Flags */
RUN_TIME[2],		/* Wakeup time (/DELAY or /SCHEDULE) */
RUN_INTERVAL[2];	/* Wakeup interval (/INTERVAL) */

/***=0C***/

int main()
{
 char pid_buf[10];				/* Buffer for ASCII PID */

 $DESCRIPTOR(run_pid,"$RUN_PID");		/* Symbol name */
 $DESCRIPTOR(dcl_ide,"IDENTIFY");

 $DESCRIPTOR(pid,pid_buf);			/* Descriptor for ASCII PID */

 /* Obtain process information. */

 get_prcinf();
=20
 /* Obtain image name and all command qualifiers. */

 get_cmdlin();

 /* Now create new process. */

 creprc();

 /* Unless disabled, print PID. */

 if (cli$present(&dcl_ide) !=3D CLI$_NEGATED)

 lib$signal(RUN$_PROC_ID,1,RUN_PID);

 /* Place PID in symbol $RUN_PID. */

 sprintf(pid_buf,"%08X",RUN_PID);

 pid.dsc$w_length =3D 8;

 lib$set_symbol(&run_pid,&pid,&LIB$K_CLI_GLOBAL_SYM);

 /* Well, all done. */

 return SS$_NORMAL;
}

/***=0C***/

void get_prcinf()
{
 /* This routine obtains information about our process.
    We'll require this information later. */

 short iosb[4];				/* GETJPI I/O status block */

 int status;				/* Return status; */

 struct itmlst itm[5] =3D 		/* Item list for SYS$JPI: */
 {=20
  4, JPI$_PRIB,    &RUN_PRIORITY,0,	/* Default priority */
  8, JPI$_PROCPRIV,RUN_PRIVS,0,		/* Process privileges */
  8, JPI$_PROCPRIV,OUR_PRIVS,0,		/* Copy for later checks */
  16,JPI$_USERNAME,(int*) OUR_USRNAM,0,	/* Username */
  0,0

 };					/* End of list */

 /* Call SYS$GETJPI to obtain this information. */

 if ((status =3D sys$getjpiw(0,0,0,itm,iosb,0,0)) !=3D SS$_NORMAL)

 lib$signal(RUN$_GETJPI,0,status);

 /* Error in IOSB? Signal as well. */

 if (iosb[0] !=3D SS$_NORMAL) lib$signal(RUN$_GETJPI,0,iosb[0]);

 /* The username is returned as blank-filled string. Shrink it
    to its actual length. */

 OUR_USRNAM[strcspn(OUR_USRNAM," ")] =3D '\0';

 /* OK, thats all. */
}=20

/***=0C***/

void get_cmdlin()
{
 /* This routine obtains all information specified in
    the command line: the image parameter and all qualifiers. */

 int status;				/* CLI$xxx return status */

 /* Command qualifier names: */

 $DESCRIPTOR(dcl_inp,"INPUT");
 $DESCRIPTOR(dcl_out,"OUTPUT");
 $DESCRIPTOR(dcl_err,"ERROR");
 $DESCRIPTOR(dcl_nam,"PROCESS_NAME");
 $DESCRIPTOR(dcl_pri,"PRIORITY");
 $DESCRIPTOR(dcl_mbx,"MAILBOX");

 $DESCRIPTOR(dcl_acc,"ACCOUNTING");
 $DESCRIPTOR(dcl_aut,"AUTHORIZE");
 $DESCRIPTOR(dcl_det,"DETACHED");
 $DESCRIPTOR(dcl_dmp,"DUMP");
 $DESCRIPTOR(dcl_res,"RESOURCE_WAIT");
 $DESCRIPTOR(dcl_fai,"SERVICE_FAILURE");
 $DESCRIPTOR(dcl_swp,"SWAPPING");

#ifdef VMS_V6		/* Available in VMS V6 and higher only: */
 $DESCRIPTOR(dcl_tcb,"TRUSTED");
#ifdef VMS_V7		/* Available in VMS V7 and higher only: */
 $DESCRIPTOR(dcl_nod,"ON");
#endif
#endif

 /* First, get and parse the image name ('filename' parameter). */

 get_imgnam();

 /* Next, get all string values. */

 get_string(&dcl_inp,RUN_INPUT,255);		/* /INPUT */

 get_string(&dcl_out,RUN_OUTPUT,255);		/* /OUTPUT */

 get_string(&dcl_err,RUN_ERROR,255);		/* /ERROR */

 get_string(&dcl_nam,RUN_PRCNAM,15);		/* /PROCESS_NAME */

#ifdef VMS_V7
 get_string(&dcl_nod,RUN_NODNAM,6);		/* /ON */
#endif

 /* Get SYS$CREPRC flags. */

 chk_flg(&dcl_acc,PRC$M_NOACNT,1);		/* /NOACCOUNTING */

 chk_flg(&dcl_aut,PRC$M_NOUAF,1);		/* /NOAUTHORIZE */

 chk_flg(&dcl_det,PRC$M_DETACH,0);		/* /DETACHED */

 chk_flg(&dcl_dmp,PRC$M_IMGDMP,0);		/* /DUMP */

 chk_flg(&dcl_res,PRC$M_SSRWAIT,1);		/* /NORESOURCE_WAIT */

 chk_flg(&dcl_fai,PRC$M_SSFEXCU,0);		/* /SERVICE_FAILURE */

 chk_flg(&dcl_swp,PRC$M_PSWAPM,1);		/* /NOSWAPPING */

#ifdef VMS_V6
 chk_flg(&dcl_tcb,PRC$M_TCB,0);			/* /TRUSTED */
#endif

 /* Get and validate specified username. */

 get_usrnam();					/* /USERNAME */

 /* Get and validate specified UIC. */

 get_uic();					/* /UIC */
=20
 /* Get specified priority. */

 get_value(&dcl_pri,&RUN_PRIORITY);		/* /PRIORITY */

 /* And termination mailbox unit number. */

 get_value(&dcl_mbx,&RUN_MBXUNIT);		/* /MAILBOX */

 /* Get quotas. */

 get_quotas();

 /* Get privileges. */				/* /PRIVILEGES */

 get_privs();

 /* Get time values */				/* /DELAY,/INTERVAL,/SCHEDULE */

 get_times();

 /* That's all! */
}

/***=0C***/

void get_imgnam()
{
 /* This routine obtains and parses the specified image name. */

 short
 retlen;			/* Return length */

 int
 status,			/* Return status */
 secstat,			/* Secondary status */
 ctx =3D 0;			/* Context for LIB$FIND_FILE */

 $DESCRIPTOR(dcl_img,"P1");	/* Parameter name */
 $DESCRIPTOR(defnam,".EXE");	/* Default file type */
 $DESCRIPTOR(resnam, FUL_IMAGE); /* Resultant image name */

 $DESCRIPTOR(aux," ");		/* Auxiliary descriptor */

 aux.dsc$w_length =3D 255;

 aux.dsc$a_pointer =3D RUN_IMAGE;

 cli$get_value(&dcl_img,&aux,&retlen);

 RUN_IMAGE[retlen] =3D '\0';

 aux.dsc$w_length =3D retlen;

 /* Parse the image name (".EXE" is default file type). */

 status =3D lib$find_file(&aux,&resnam,&ctx,&defnam,0,&secstat,&1);

 if (status !=3D RMS$_NORMAL) lib$signal(RUN$_PARSEFAIL,1,&aux,status,sec=
stat);

 FUL_IMAGE[strcspn(FUL_IMAGE," ")] =3D '\0';

 /* LIB$FIND_FILE returns the full file specification, including the
    version number. However, if the user hasn't specified a version
    number, we must remove it from the full file spec as well. Other-
    wise, even images installed shareable and/or with elevated privs
    would be activated without privs and process-private. */

 if (!strchr(RUN_IMAGE,';')) *(strchr(FUL_IMAGE,';')) =3D '\0';

 /* That's all. */
}

/***=0C***/

void get_string(struct dsc$descriptor_s *ptr, char *retbuf, int maxlen)
{
 /* This routine obtains the CLI item whose name is specified in 'ptr'
    and returns the approbiate string in 'retbuf'. 'maxlen' determines
    the maximum size of 'retbuf'. */

 short retlen =3D 0;

 $DESCRIPTOR(aux,retbuf);

 if (cli$present(ptr) =3D=3D CLI$_PRESENT)
 {
  aux.dsc$w_length =3D maxlen;

  cli$get_value(ptr,&aux,&retlen);
 }
 retbuf[retlen] =3D '\0';
}

/***=0C***/

void chk_flg(struct dsc$descriptor_s *ptr, int bitval, int negated)
{
 /* This routine checks whether the specified CLI item (name in 'ptr')
    is present or negated in the command line. It sets the bit specified
    in 'bitval' if the item is present ('negated' =3D 0) or if it is
    explicitly negated ('negated' =3D 1). */

 int status =3D cli$present(ptr);

 if (status =3D=3D CLI$_PRESENT && !negated) RUN_FLAGS |=3D bitval;

 if (status !=3D CLI$_PRESENT && negated) RUN_FLAGS |=3D bitval;
}

/***=0C***/

void get_usrnam()
{
 /* Obtains username and validates it. */

 int grp;					/* To save group ID */

 $DESCRIPTOR(dcl_usr,"USER");			/* DCL qualifier name */

 $DESCRIPTOR(aux,RUN_USRNAM);			/* Aux descriptor */

 get_string(&dcl_usr,RUN_USRNAM,16);		/* Get value */

 if (!RUN_USRNAM[0]) return;			/* Return if no name */

 aux.dsc$w_length =3D strlen(RUN_USRNAM); 	/* Set descriptor */

 /* If the specified name is longer than 12 chars, return error. */

 if (aux.dsc$w_length > 12) lib$signal(RUN$_INVQUAVAL,2,&aux,&dcl_usr);

 /* In addition, if /AUTHORIZE is specified, ensure that the given
    username exists in the UAF, obtains its UIC and provide it as
    default. */

 if (!(RUN_FLAGS & PRC$M_NOUAF))
 {
  if (sys$asctoid(&aux,&RUN_UIC,0) !=3D SS$_NORMAL)=20

  lib$signal(RUN$_INVQUAVAL,2,&aux,&dcl_usr);

  /* Ensure that the obtained UIC is in valid range. */

  grp =3D RUN_UIC >> 16;

  if ((RUN_UIC & 0177777) > 0177776 || grp > 037776)

  lib$signal(RUN$_INVQUAVAL,2,&aux,&dcl_usr);
 }
 /* Keep in mind that we must create a detached process. */

 RUN_FLAGS |=3D PRC$M_DETACH;
}

/***=0C***/

void get_uic()
{
 /* Obtains UIC string and checks for valid syntax. */

 char
 *ptr,					/* Aux pointer */
 aux_buf[44];				/* Buffer receiving UIC */

 int grp;				/* Group value */

 $DESCRIPTOR(dcl_uic,"UIC");		/* DCL qualifier name */

 $DESCRIPTOR(aux,aux_buf);		/* Aux. descriptor */

 get_string(&dcl_uic,aux_buf,44);	/* Get UIC value */

 aux.dsc$w_length =3D strlen(aux_buf);	/* Update descriptor */

 if (aux_buf[0])			/* UIC was specified */
 {
  if (aux_buf[0] =3D=3D '[' || aux_buf[0] =3D=3D '<')	/* Starts with '[' =
or '<'? */
  {
   if (aux_buf[1] >=3D '0' && aux_buf[1] <=3D '7')	/* Octal UIC was given=
 */
   {
    /* If not syntax [grp,mem] or <grp_mem>, return error. */

    if (aux_buf[0] =3D=3D '[')
    {
     if (sscanf(aux_buf,"[%o,%o]",(short*) &grp,(int*) &RUN_UIC) !=3D 2)

     lib$signal(RUN$_INVUIC,1,&aux);
    }
    else
    {
     if (sscanf(aux_buf,"<%o,%o>",(short*) &grp,(int*) &RUN_UIC) !=3D 2)

     lib$signal(RUN$_INVUIC,1,&aux);
    }
    /* If grp and member values are out of range, return error. */

    if (grp > 037776 || RUN_UIC > 0177776) lib$signal(RUN$_INVUIC,1,&aux)=
;

    RUN_UIC +=3D grp*65536;			/* Compute actual UIC */

    return;					/* and return */
   }
   /* UIC starts with '[', but contains an identifier name. Update
      descriptor. */

   aux.dsc$a_pointer++;

   aux.dsc$w_length -=3D 2;
  }
  /* Translate identifier name to binary value. If it fails, return error=
. */

  if (sys$asctoid(&aux,&RUN_UIC,0) !=3D SS$_NORMAL) lib$signal(RUN$_INVUI=
C,1,&aux);
 }
 /* Well, that's all. */
}

/***=0C***/

void get_value(struct dsc$descriptor_s *ptr, int *retval)
{
 /* This routine obtains the CLI item whose name is specified in
    'ptr', converts it to an integer value and returns this value
    to retval. */

 char auxbuf[16];		/* Aux. buffer */

 short retlen;			/* Return length */

 $DESCRIPTOR(aux,auxbuf);

 if (cli$present(ptr) =3D=3D CLI$_PRESENT)
 {
  cli$get_value(ptr,&aux,&retlen);

  auxbuf[retlen] =3D '\0';

  aux.dsc$w_length =3D retlen;

  if (sscanf(auxbuf,"%d",retval) !=3D 1)

  lib$signal(RUN$_CVTERR,2,ptr,&aux,LIB$_INVNBDS);
 }
}

/***=0C***/

void get_quotas()
{
 /* This routine obtains all quotas from the command line and
    fills in the quota list which is later passed to SYS$CREPRC. */

 char cputimbuf[16];			/* ASCII cputime */

 int
 bintim[2],				/* Binary CPU time */
 cnt =3D 0;				/* Contains curr. quota item # */

 $DESCRIPTOR(cputim,cputimbuf);		/* Descriptor to ASCII CPU time; */

 $DESCRIPTOR(dcl_ast,"AST_LIMIT");
 $DESCRIPTOR(dcl_buf,"BUFFER_LIMIT");
 $DESCRIPTOR(dcl_equ,"ENQUEUE_LIMIT");
 $DESCRIPTOR(dcl_ext,"EXTENT");
 $DESCRIPTOR(dcl_fil,"FILE_LIMIT");
 $DESCRIPTOR(dcl_iob,"IO_BUFFERED");
 $DESCRIPTOR(dcl_iod,"IO_DIRECT");
 $DESCRIPTOR(dcl_job,"JOB_TABLE_QUOTA");
 $DESCRIPTOR(dcl_wsm,"MAXIMUM_WORKING_SET");
 $DESCRIPTOR(dcl_pag,"PAGE_FILE");
 $DESCRIPTOR(dcl_que,"QUEUE_LIMIT");
 $DESCRIPTOR(dcl_sub,"SUBPROCESS_LIMIT");
 $DESCRIPTOR(dcl_tim,"TIME_LIMIT");
 $DESCRIPTOR(dcl_wrk,"WORKING_SET");

 /* Get all quotas. If a quota was specified, obtains its value
    and place it in the next free quota list entry. */

 if (cli$present(&dcl_ast) =3D=3D CLI$_PRESENT)	/* AST limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_ASTLM;

  get_value(&dcl_ast,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_buf) =3D=3D CLI$_PRESENT)	/* Buffer (Byte) Limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_BYTLM;

  get_value(&dcl_buf,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_equ) =3D=3D CLI$_PRESENT)	/* Enqueue (lock) limit *=
/
 {
  RUN_QUOTA[cnt].code =3D PQL$_ENQLM;

  get_value(&dcl_equ,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_ext) =3D=3D CLI$_PRESENT)	/* Working set limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_WSEXTENT;

  get_value(&dcl_ext,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_fil) =3D=3D CLI$_PRESENT)	/* Open file limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_FILLM;

  get_value(&dcl_fil,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_iob) =3D=3D CLI$_PRESENT)	/* Buffered I/O limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_BIOLM;

  get_value(&dcl_iob,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_iod) =3D=3D CLI$_PRESENT)	/* Direct I/O limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_DIOLM;

  get_value(&dcl_iod,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_job) =3D=3D CLI$_PRESENT)	/* Job log. name table qu=
ota */
 {
  RUN_QUOTA[cnt].code =3D PQL$_JTQUOTA;

  get_value(&dcl_job,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_wsm) =3D=3D CLI$_PRESENT)	/* Working set quota */
 {
  RUN_QUOTA[cnt].code =3D PQL$_WSQUOTA;

  get_value(&dcl_wsm,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_pag) =3D=3D CLI$_PRESENT)	/* Page file quota */
 {
  RUN_QUOTA[cnt].code =3D PQL$_PGFLQUOTA;

  get_value(&dcl_pag,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_que) =3D=3D CLI$_PRESENT)	/* Timer queue limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_TQELM;

  get_value(&dcl_que,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_sub) =3D=3D CLI$_PRESENT)	/* Subprocess limit */
 {
  RUN_QUOTA[cnt].code =3D PQL$_PRCLM;

  get_value(&dcl_sub,&RUN_QUOTA[cnt++].val);
 }
 if (cli$present(&dcl_wrk) =3D=3D CLI$_PRESENT)	/* Working set default */
 {
  RUN_QUOTA[cnt].code =3D PQL$_WSDEFAULT;

  get_value(&dcl_wrk,&RUN_QUOTA[cnt++].val);
 }
 /* CPU time quota. On the DCL command line, it is given as VMS
    delta time, however, in the quota list, it must be specified
    in units of 10 ms. */

 if (cli$present(&dcl_tim) =3D=3D CLI$_PRESENT)	/* If specified */
 {
  get_string(&dcl_tim,cputimbuf,14);		/* Get the string */

  cputim.dsc$w_length =3D strlen(cputimbuf);	/* Update descriptor length =
*/

  if (sys$bintim(&cputim,bintim) !=3D SS$_NORMAL)	/* Convert it to binary=
 */

  lib$signal(RUN$_ILLVAL,1,&cputim);		/* If error, signal */

  if (lib$ediv(&-200000,&bintim[0],&bintim[0],&bintim[1]) !=3D SS$_NORMAL=
)

  lib$signal(RUN$_ILLVAL,1,&cputim);		/* If error, signal */

  RUN_QUOTA[cnt].code =3D PQL$_CPULM;

  RUN_QUOTA[cnt++].val =3D bintim[0] * 2 + bintim[1];
 }
 /* Mark the end of the list. */

 RUN_QUOTA[cnt].code =3D PQL$_LISTEND;

 /* If at least one quota was specified, set the pointer to the
    quota list. */

 if (cnt) RUN_QUOLIST =3D RUN_QUOTA;

 /* That's all. */
}

/***=0C***/

void get_privs()
{
 /* This routine processes the privilege list given in the /PRIVILEGES
    qualifier and sets the RUN_PRIVS privilege mask accordingly. */

 char *ptr,					/* Aux. pointer */
 aux_buf[12];					/* Receives priv keywords */

 short
 retlen;					/* Return length */

 int
 msk,						/* Mask number */
 value,						/* Privilege value */
 status;					/* Return status */

 $DESCRIPTOR(dcl_prv,"PRIVILEGES");
 $DESCRIPTOR(dcl_sam,"PRIVILEGES.SAME");
 $DESCRIPTOR(aux, aux_buf);			/* Aux. descriptor */

 /* First, check for /PRIVILEGES=3DNOSAME. If this is specified, we must
    clear the privilege mask (NOSAME means no privileges). */

 if (cli$present(&dcl_sam) =3D=3D CLI$_NEGATED) RUN_PRIVS[0] =3D RUN_PRIV=
S[1] =3D 0;

 /* Now, look for privileges. */

 if (cli$present(&dcl_prv) =3D=3D CLI$_PRESENT)
 {
  status =3D cli$get_value(&dcl_prv,&aux,&retlen);

  while (status !=3D CLI$_ABSENT)
  {
   aux_buf[retlen] =3D '\0';

   ptr =3D aux_buf;				/* Point to priv name */

   /* If NO<prv> was specified, adjust pointer. */

   if (aux_buf[0] =3D=3D 'N' && aux_buf[1] =3D=3D 'O') ptr +=3D 2;

   /* IF [NO]ALL was specified, this means either (no) all privileges
      or (no) ALLSPOOL privilege. If the string length is 3, we assume
      ALL, otherwise ALLSPOOL. Note that in the case of ALL, the
      string must be at least 3 bytes, due the ambiguity with ALTPRI. */

   if (strlen(ptr) =3D=3D 3)				/* Length =3D 3? */
   {
    if (!strcmp(ptr,"ALL"))				/* [NO]ALL ? */
    {
     if (aux_buf[0] =3D=3D 'N' && aux_buf[1] =3D=3D 'O')	/* NOALL? */
    =20
     RUN_PRIVS[0] =3D RUN_PRIVS[1] =3D 0;			/* Clear all privs */

     else RUN_PRIVS[0] =3D RUN_PRIVS[1] =3D -1;		/* else set all privs */

     status =3D cli$get_value(&dcl_prv,&aux,&retlen);	/* Get next priv */

     continue;						/* and proceed */
    }=20
   }  =20
   value =3D get_prvval(ptr,&msk);			/* Get mask value */

   if (aux_buf [0] =3D=3D 'N' && aux_buf [1] =3D=3D 'O')	/* IF NO<priv> *=
/

   RUN_PRIVS[msk] &=3D ~value;				/* Clear appr. bit */

   else RUN_PRIVS[msk] |=3D value;			/* Else set appr. bit */

   status =3D cli$get_value(&dcl_prv,&aux,&retlen);
  }
 }
 /* OK, that's all. */
}

/***=0C***/

int get_prvval(char *prvnam,int *msk)
{
 /* Given the privilege name in 'prvnam', this routine obtain the
    approbiate privilege mask value and returns it to its caller.
    'msk' is set to 0 if the privilege is in the lower 32 bit range,
    or set to 1, if the privilege bit is in the upper 32 bit range.

    Parsing was already done by DCL, so we can be sure that
    unambiguous privilege names were passed only. If the privilege
    name is 'SAME', ignore it (return 0) since it was already
    processed earlier. */

 $DESCRIPTOR(aux, prvnam);		/* Aux. descriptor */
 $DESCRIPTOR(prv,"PRIVILEGES");		/* For message string */

 /* Most privileges are in the lower 32 bit range, so assume 'msk'
    to be 0. */

 *msk =3D 0;

 switch (prvnam[0])		/* Check first letter. */
 {
  case 'A':
  {
   switch (prvnam[1])
   {
    case 'C': return PRV$M_ACNT;
    case 'L':
    {
     switch (prvnam[2])
     {
      case 'L': return PRV$M_ALLSPOOL;
      case 'T': return PRV$M_ALTPRI;
     }
    }
#ifdef VMS_V6
    case 'U': {*msk =3D 1; return PRV$M_AUDIT;}
#endif
   }
  }
  case 'B':
  {
   switch (prvnam[1])
   {
    case 'U': return PRV$M_BUGCHK;
    case 'Y': return PRV$M_BYPASS;
   }
  }
  case 'C':
  {
   switch (prvnam[2])
   {
    case 'E': return PRV$M_CMEXEC;
    case 'K': return PRV$M_CMKRNL;=20
   }
  }
  case 'D':
  {
   switch (prvnam[1])
   {
    case 'E': return PRV$M_DETACH;
    case 'I': return PRV$M_DIAGNOSE;
#ifdef VMS_V6
    case 'O': {*msk =3D 1; return PRV$M_DOWNGRADE;}
#endif
   }
  }
  case 'E': return PRV$M_EXQUOTA;

  case 'G':
  {
   switch (prvnam[3])
   {
    case 'N': return PRV$M_GRPNAM;
    case 'P': {*msk =3D 1; return PRV$M_GRPPRV;}
    case 'U': return PRV$M_GROUP;
   }
  }
  case 'I':
  {
#ifdef VMS_V6
   switch (prvnam[3])
   {
    case 'O': {*msk =3D 1; return PRV$M_IMPORT;}
#ifdef VMS_V7
    case 'E': return PRV$M_IMPERSONATE;
#endif
   }=20
#endif
  }
  case 'L': return PRV$M_LOG_IO;

  case 'M': return PRV$M_MOUNT;

  case 'N': return PRV$M_NETMBX;

  case 'O': return PRV$M_OPER;

  case 'P':
  {
   switch (prvnam[1])
   {
    case 'F': return PRV$M_PFNMAP;
    case 'H': return PRV$M_PHY_IO;
    case 'R':
    {
     switch (prvnam[3])
     {
      case 'C': return PRV$M_PRMCEB;
      case 'G': return PRV$M_PRMGBL;
      case 'M': return PRV$M_PRMMBX;
     }
    }
    case 'S': return PRV$M_PSWAPM;
   }
  }
  case 'R': {*msk =3D 1; return PRV$M_READALL;}

  case 'S':
  {
   switch (prvnam[1])
   {
    case 'A': return 0;			/* Do not process SAME here */
    case 'E':
    {
     switch (prvnam[2])
     {
      case 'C': {*msk =3D 1; return PRV$M_SECURITY;}
      case 'T': return PRV$M_SETPRV;
     }
    }
    case 'H':
    {
     switch(prvnam[2])
     {
      case 'A': return PRV$M_SHARE;
      case 'M': return PRV$M_SHMEM;
     }
    }
    case 'Y':
    {
     switch(prvnam[3])
     {
      case 'G': return PRV$M_SYSGBL;
      case 'L': return PRV$M_SYSLCK;
      case 'N': return PRV$M_SYSNAM;
      case 'P': return PRV$M_SYSPRV;
     }
    }
   }
  }
  case 'T':
  {
   switch (prvnam[3])
   {
    case 'M': return PRV$M_TMPMBX;
   }
  }
#ifdef VMS_V6
  case 'U': {*msk =3D 1; return PRV$M_UPGRADE;}
#endif
  case 'V': return PRV$M_VOLPRO;

  case 'W': return PRV$M_WORLD;
 }
 /* If we come here, we have lost. Build a descriptor to the
    incorrect privilege name. */

 aux.dsc$w_length =3D strlen(prvnam);

 /* Signal the error. */

 lib$signal(RUN$_INVQUAVAL,2,&prv,&aux);
}

/***=0C***/

void get_times()
{
 /* This routine obtains the times given by /DELAY, /INTERVAL and
    /SCHEDULE. */

 char
 timbuf[44];					/* Buffer for ASCII time */

 $DESCRIPTOR(dcl_del,"DELAY");
 $DESCRIPTOR(dcl_int,"INTERVAL");
 $DESCRIPTOR(dcl_sch,"SCHEDULE");

 $DESCRIPTOR(tim,timbuf);			/* Descriptor for $BINTIM */

 get_string(&dcl_del,timbuf,43);		/* /DELAY */

 if (timbuf[0])					/* Was /DELAY given? */
 {
  tim.dsc$w_length =3D strlen(timbuf);		/* Yes, set descriptor */

  if (sys$bintim(&tim,RUN_TIME) !=3D SS$_NORMAL)	/* Convert it */

  lib$signal(RUN$_CVTERR,2,&dcl_del,&tim);	/* If error, signal */

  RUN_FLAGS |=3D PRC$M_HIBER;			/* Mark process to hibernate */
 }
 get_string(&dcl_int,timbuf,43);		/* Same for /INTERVAL */

 if (timbuf[0])
 {
  tim.dsc$w_length =3D strlen(timbuf);

  if (sys$bintim(&tim,RUN_INTERVAL) !=3D SS$_NORMAL)

  lib$signal(RUN$_CVTERR,2,&dcl_int,&tim);

  RUN_FLAGS |=3D PRC$M_HIBER;
 }
 get_string(&dcl_sch,timbuf,43);		/* /SCHEDULE */

 if (timbuf[0])
 {
  tim.dsc$w_length =3D strlen(timbuf);

  if (sys$bintim(&tim,RUN_TIME) !=3D SS$_NORMAL)

  lib$signal(RUN$_CVTERR,2,&dcl_sch,&tim);

  RUN_FLAGS |=3D PRC$M_HIBER;
 }
}

/***=0C***/

void creprc()
{
 /* This routine performs the actual process creation based on the argume=
nts
    evaluated in get_cmdlin(). */

 int
 creprc_status,					/* Status of SYS$CREPRC */
 schdwk_status =3D SS$_NORMAL,			/* Status of SYS$SCHDWK */
 newmsk =3D LIB$M_CLI_CTRLY,			/* mask to disable CTRL-Y */
 oldmsk;					/* Old CTRL mask */

 $DESCRIPTOR(usr,RUN_USRNAM);			/* Descriptor for username */
 $DESCRIPTOR(img,FUL_IMAGE);			/* Descriptor for various */
 $DESCRIPTOR(inp,RUN_INPUT);			/* input arguments */
 $DESCRIPTOR(out,RUN_OUTPUT);
 $DESCRIPTOR(err,RUN_ERROR);
 $DESCRIPTOR(nam,RUN_PRCNAM);
#ifdef VMS_V7
 $DESCRIPTOR(nod,RUN_NODNAM);
#endif

 /* Initialize all descriptors. */

 img.dsc$w_length =3D strlen(FUL_IMAGE);
 inp.dsc$w_length =3D strlen(RUN_INPUT);
 out.dsc$w_length =3D strlen(RUN_OUTPUT);
 err.dsc$w_length =3D strlen(RUN_ERROR);
 nam.dsc$w_length =3D strlen(RUN_PRCNAM);
#ifdef VMS_V7
 nod.dsc$w_length =3D strlen(RUN_NODNAM);
#endif

 /* If /USER was given, we need DETACH and CMKRNL privileges. */

 if (RUN_USRNAM[0])
 {
  if (!(OUR_PRIVS[0] & PRV$M_CMKRNL))		/* Lack of CMKRNL */

  lib$signal(RUN$_CREPRC,0,SS$_NOCMKRNL);	/* Signal if missing */

  if (!(OUR_PRIVS[0] & PRV$M_DETACH))		/* Same for DETACH */

  lib$signal(RUN$_CREPRC,0,SS$_NODETACH);	/* Signal if missing */

  /* Change our username before calling $CREPRC. This will force
     the new process to be created under this name. First, disable
     CTRL-Y temporary. */

  lib$disable_ctrl(&newmsk,&oldmsk);

  usr.dsc$w_length =3D strlen(RUN_USRNAM);	/* Setup descriptor */

  if ((creprc_status =3D _setnam(&usr)) !=3D SS$_NORMAL)	/* Change name *=
/

  lib$signal(RUN$_CREPRC,0,creprc_status);
 }
 /* Create the process. */

 creprc_status =3D sys$creprc(&RUN_PID,		/* Longword to receive PID */
			&img,			/* Image name */
			&inp,			/* Input file name */
			&out,			/* Output file name */
			&err,			/* Error file name */
			RUN_PRIVS,		/* Privileges */
			RUN_QUOLIST,		/* Quota list (or 0) */
			&nam,			/* Process name */
			RUN_PRIORITY,		/* Base priority */
			RUN_UIC,		/* Process UIC */
			RUN_MBXUNIT,		/* Termination mailbox */
#ifdef VMS_V7
			RUN_FLAGS,		/* Process flags */
			0,			/* Item list (not used) */
			RUN_NODNAM);		/* Node name */
#else
			RUN_FLAGS);		/* Process flags */
#endif

 /* If process creation was successful and hibernation was requested due
    to qualifiers /DELAY, /INTERVAL or /SCHEDULE), schedule the wakeup
    request now. */

 if (creprc_status =3D=3D SS$_NORMAL && RUN_FLAGS & PRC$M_HIBER)

 schdwk_status =3D sys$schdwk(&RUN_PID,0,RUN_TIME,RUN_INTERVAL);

 /* If username was changed temporary, set it back. */

 if (RUN_USRNAM[0])
 {
  usr.dsc$w_length =3D strlen(OUR_USRNAM);		/* Setup descriptor */
  usr.dsc$a_pointer =3D OUR_USRNAM;

  _setnam(&usr);					/* Restore username */

  lib$enable_ctrl(&oldmsk);				/* Restore CTRL-Y */
 }
 /* If process creation or schedule wakeup failed for some reason,
    let the user know. */

 if (creprc_status !=3D SS$_NORMAL)

 lib$signal(RUN$_CREPRC,1,RUN_PID,creprc_status);

 if (schdwk_status !=3D SS$_NORMAL)

 lib$signal(RUN$_SCHDWK,1,RUN_PID,schdwk_status);
}

=0C---------------------->>> #6: ADV_RUNUSR_MSG.MSG <<<------------------=
----

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
! Message codes for RUNUSR.
! -------------------------
!
! These codes were obtain by the UNMESSAGE utility.
!
	.facility	RUN, 192/system/prefix=3DRUN$_

	.severity	success
	PROC_ID		<identification of created process is !XL>

	.severity	warning
	SCHDWK		<failed to schedule wake up request for process !XL>

	.severity	fatal
	CREPRC		<process creation failed>
	GETJPI		<failed to obtain default job and process information>
	CVTERR		<could not convert entity !AS using !AS>
	INVUIC		<!AS is an invalid UIC specification>
	ILLVAL		<!AS is an illegal CPU time>

        .end

=0C---------------------->>> #7: ADV_RUNUSR_V5.HLP <<<-------------------=
---

1  RUN
   Executes an image within the context of your process (see Image).

   Creates a subprocess or a detached process to run an image and
   deletes the process when the image completes execution (see
   Process).


2  Image
   Executes an image within the context of your process. You can
   abbreviate the RUN command to a single letter, R.

   If you specify an image name in the command line with an explicit
   version number (or a semicolon [;]), the image runs with current
   process privileges. If you do not specify an explicit version
   number (or semicolon), the image runs with any privileges with
   which it was installed. If you have DECnet software installed and
   want to execute an image over the network, you must have read (R)
   access to the file.

   Format

     RUN  filespec
=20

3  PARAMETER
=20

   filespec

   Specifies an executable image to be executed. The file type
   defaults to EXE. Wildcard characters are not allowed.
=20

3  QUALIFIER
=20

/DEBUG

      /DEBUG
      /NODEBUG

   Executes the image under control of the debugger. The default is
   the /DEBUG qualifier if the image is linked with the /DEBUG
   qualifier and the /NODEBUG qualifier if the image is linked
   without the /DEBUG qualifier. The /DEBUG qualifier is invalid if
   the image is linked with the /NOTRACEBACK qualifier. The
   /NODEBUG qualifier overrides the effect of the LINK/DEBUG
   command. If the image was linked with the /TRACEBACK qualifier,
   traceback reporting is performed when an error occurs.

   If the image was not linked with the debugger, you can specify
   the /DEBUG qualifier to request the debugger at execution time.
   However, if the /NOTRACEBACK qualifier was specified when the
   image was linked, the /DEBUG qualifier is invalid.

   For a complete description of the VMS Debugger, see the VMS
   Debugger Manual.

   To get help on debugger commands from DCL level, type the
   following command:

   $ HELP/LIBRARY=3DSYS$HELP:DBG$HELP

3  Examples

  1.$ RUN LIBRA

    The image LIBRA.EXE starts executing in the process. If the
    image LIBRA has been installed with amplified privileges, it
    runs with those privileges because you have not explicitly
    specified a version number or a semicolon. Alternatively, the
    image LIBRA.EXE still runs with its amplified privileges, if
    you enter the RUN command as follows:

        $ RUN LIBRA.EXE

  2.  $ MACRO/ENABLE=3DDEBUG ORION
      $ LINK/DEBUG ORION
      $ RUN ORION

           VAX DEBUG Version 5.5
=20

      %DEBUG-I-INITIAL, language is MACRO, module set to 'ORION'
      DBG>
         .
         .
         .
      $ RUN/NODEBUG ORION

    A program is compiled, linked, and run with the debugger.
    Subsequently, a RUN/NODEBUG command requests that the
    debugger, which is present in the image, not issue a prompt.
    If an error occurs while the image executes, the debugger can
    perform traceback and report on the error.

  3.  $ RUN AQUARIUS.EXE;1

    The image AQUARIUS.EXE starts executing in the process. If the
    image AQUARIUS has been installed with amplified privileges,
    it does not run with those privileges because you have
    specified a version number. Instead, the image runs with
    current process privileges only. When you specify a version
    number (or even just a semicolon), the image activator does
    not search its list of special images that have been installed
    with privileges. The process AQUARIUS still runs with only
    normal process privileges if you enter the RUN command as
    follows:

      $ RUN AQUARIUS.EXE;

    In this case, however, the highest version of the image
    AQUARIUS runs.

2  Process
   Creates a subprocess or a detached process to run an image
   and deletes the process when the image completes execution.
   A subprocess is created if any of the qualifiers except /UIC,
   /USER or /DETACHED is specified. A detached process is
   created if the /UIC, /USER or the /DETACHED qualifier is
   specified and you have DETACH user privilege.

   Format

     RUN  filespec

3  PARAMETER

filespec
   Specifies the file name of an executable image to be executed
   in a separate process. The default file type is EXE. Wildcard
   characters are not allowed in the file specification.

3  QUALIFIERS

/ACCOUNTING

      /ACCOUNTING (default)
      /NOACCOUNTING

   Requires ACNT (accounting) privilege to disable accounting.

   Logs accounting records in the system accounting file for the
   created process.

/AST_LIMIT

      /AST_LIMIT=3Dquota

   Specifies the maximum number of asynchronous system traps (ASTs)
   that the created process can have outstanding.

   If you do specify an AST limit quota, the default quota
   established at system generation time is used. The minimum
   required for any process to execute is 2. A value of 10 is
   typical.

   The AST limit quota is nondeductible.

/AUTHORIZE

      /AUTHORIZE
      /NOAUTHORIZE (default)

   Requires DETACH privilege.

   When the image to be executed is the system login image
   (LOGINOUT.EXE), this qualifier searches the user authorization
   file (UAF) to validate a detached process. The /NOAUTHORIZE
   qualifier creates a detached process that runs under the control
   of the command interpreter.

   When specifying /USER and /AUTHORIZE, the detached process' UIC
   is obtained from the UAF; in this case, a valid username must
   be supplied. Specifying /NOAUTHORIZE causes the new process to
   inherit the UIC from your process; in this case, you may also
   supply a non-existant username.

/BUFFER_LIMIT

      /BUFFER_LIMIT=3Dquota

   Specifies the maximum amount of memory, in bytes, that the process
   can use for buffered I/O operations or for temporary mailbox
   creation.

   If you do not specify a buffered I/O quota, the default value
   established at system generation time is used. The minimum amount
   required for any process to execute is 1024 bytes. A value of
   10,240 is typical.

   The buffer limit quota is pooled.

/DELAY

      /DELAY=3Ddelta-time

   Places the created process in hibernation and awakens it after a
   specified time interval.

   Specify the delta time according to the rules for entering delta
   times given in the VMS DCL Concepts Manual.

   If you specify both the /DELAY and /INTERVAL qualifiers, the
   first wakeup request occurs at the time specified by the /DELAY
   qualifiers. All subsequent wakeup requests occur at the interval
   specified by the /INTERVAL qualifier.

/DETACHED

      /DETACHED
      /NODETACHED

   Creates a detached process with the same user identification code
   (UIC) as the current process. (To create a detached process with
   a different UIC, use the /UIC qualifier.) By default, the created
   process is not a detached process.

   By default, the detached process has the same resource quotas as
   the current process; the DETACH privilege allows you to specify
   any quotas you need for the detached process. Unless you have the
   DETACH privilege, the maximum number of detached processes that
   you can create is limited to the quota defined by MAX_DETACH in
   your UAF.

/DUMP

      /DUMP
      /NODUMP (default)

   When an image terminates because of an unhandled error, the /DUMP
   qualifier causes the contents of the address space to be written
   to the file named image-name.DMP in the process's default device
   and directory. You can then use the Analyze/Process_Dump Utility
   to analyze the dump.

/ENQUEUE_LIMIT

      /ENQUEUE_LIMIT=3Dquota

   Specifies the maximum number of locks that a process can have
   outstanding at any one time.

   The default quota is that established at system generation time.
   The minimum required for any process to operate is 2. A value of 6
   is typical.

/ERROR

      /ERROR=3Dfilespec

   Defines an equivalence name string of 1 to 63 alphanumeric
   characters for the logical device name SYS$ERROR. The logical
   name and equivalence name are placed in the process logical name
   table for the created process. (The /ERROR qualifier is ignored if
   you are running SYS$SYSTEM:LOGINOUT.)

/EXTENT

      /EXTENT=3Dquota

   Specifies the maximum size to which the image being executed in
   the process can increase its physical memory size.

   The default quota is that established at system generation time.
   The minimum value required for any process to execute is 10 pages.
   A value in the range of 400 to 2000 is typical. The extent quota
   is nondeductible.

/FILE_LIMIT

      /FILE_LIMIT=3Dquota

   Specifies the maximum number of files that a process can have open
   at any one time.

   The default quota is the quota established at system generation
   time. The minimum amount required for any process to execute is 2.
   A value of 20 is typical. The file limit quota is pooled.

/IDENTIFY

      /IDENTIFY (default)
      /NOIDENTIFY

   Displays the PID (process identification) of the created process.

/INPUT

      /INPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for
   SYS$INPUT. The logical name and equivalence name are placed in
   the process logical name table for the created process.

/INTERVAL

      /INTERVAL=3Ddelta-time

   Requests that the created process be placed in hibernation and be
   awakened at regularly scheduled intervals.

   Specify the delta time according to the rules for entering delta
   times given in the VMS DCL Concepts Manual.

   If you specify the /DELAY or the /SCHEDULE qualifier with the
   /INTERVAL qualifier, the first wakeup request occurs at the time
   specified by the /DELAY or the /SCHEDULE qualifier; all subsequent
   wakeup requests occur at intervals specified by the /INTERVAL
   qualifier. If you specify neither the /DELAY nor the /SCHEDULE
   qualifier with the /INTERVAL qualifier, the first wakeup request
   occurs immediately by default.

/IO_BUFFERED

      /IO_BUFFERED=3Dquota

   Specifies the maximum number of system-buffered I/O operations
   that the created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2. A
   value of 6 is typical. The buffered I/O quota is nondeductible.

/IO_DIRECT

      /IO_DIRECT=3Dquota

   Specifies the maximum number of direct I/O operations that the
   created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2. A
   value of 6 is typical. The direct I/O quota is nondeductible.

/JOB_TABLE_QUOTA

      /JOB_TABLE_QUOTA=3Dquota

   Allows you to specify a quota for a detached process's jobwide
   logical name table.

   A value of 0 has a special meaning. It means that the table, for
   all practical purposes, has infinite quota because its quota is
   pooled with that of its parent table, the system directory table.

   Note that the /JOB_TABLE_QUOTA qualifier is relevant only for
   detached processes. If the /JOB_TABLE_QUOTA qualifier is specified
   in a RUN command that results in the creation of a subprocess, it
   is ignored.

/MAILBOX

      /MAILBOX=3Dunit

   Specifies the unit number of a mailbox to receive a termination
   message when the created process is deleted. If no mailbox is
   specified, the creating process receives no notification when the
   subprocess or detached process has been deleted.

/MAXIMUM_WORKING_SET

      /MAXIMUM_WORKING_SET=3Dquota

   Specifies the maximum size to which the image being executed
   in the process can increase its working set size. An image can
   increase its working set size by calling the $ADJWSL (Adjust
   Working Set Limit) system service.

   The default quota is the quota established at system generation
   time. The minimum value required for any process to execute is 10
   pages. A value of 200 is typical.

   The maximum working set quota is nondeductible.

/OUTPUT

      /OUTPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for the
   logical device name SYS$OUTPUT. Both the equivalence name and the
   logical name are placed in the process logical name table for the
   created process.

/PAGE_FILE

      /PAGE_FILE=3Dquota

   Specifies the maximum number of pages that can be allocated in the
   paging file for the process. The paging file quota is the amount
   of secondary storage available during execution of the image.

   The default quota is the quota established at system generation
   time. The minimum value required for a process to execute is 256
   pages. A value of 10,000 pages is typical. The paging file quota
   is pooled.

/PRIORITY

      /PRIORITY=3Dn

   Requires ALTPRI (alter priority) privilege to set the priority
   higher than your current process.

   Specifies the base priority at which the created process executes.

   The value of the parameter n is a decimal number from 0 to 31,
   where 31 is the highest priority and zero is the lowest. Normal
   priorities range from 0 to 15; real-time priorities range from 16
   to 31.

   The default priority is that of the current process.

/PRIVILEGES

      /PRIVILEGES=3D(privilege[,...])

   Requires SETPRV (set privilege) privilege to specify privileges
   that you do not have.

   Defines user privileges for the created process. You can extend
   any privilege you possess to a process you create. By default,
   the created process has the same privileges as its creator. If you
   specify only one privilege, you can omit the parentheses.

   For a list of process privileges, see the VMS DCL Concepts Manual.

   You can also use the keyword NOSAME as the privilege parameter.
   If you specify /PRIVILEGES=3DNOSAME, the created process has no
   privileges.

   If you specify a version number (or semicolon [;]) in the filespec
   parameter, the current process privileges are used, overriding any
   privileges specified with the /PRIVILEGES qualifier.

/PROCESS_NAME

      /PROCESS_NAME=3Dprocess-name

   Specifies a name of 1 to 15 characters for the created process.
   The process name is implicitly qualified by the group number of
   the process's user identification code (UIC). By default, the name
   is null.

/QUEUE_LIMIT

      /QUEUE_LIMIT=3Dquota

   Specifies the maximum number of timer queue entries that the
   created process can have outstanding at any one time. This number
   includes timer requests and scheduled wakeup requests.

   The default quota is the quota established at system generation
   time. A process does not require any timer queue quota in order to
   execute. A value of 8 is typical.

   The timer queue entry quota is pooled.

/RESOURCE_WAIT

      /RESOURCE_WAIT (default)
      /NORESOURCE_WAIT

   Places the created process in a wait state when a resource
   required for a particular function is not available.

   If you specify the /NORESOURCE_WAIT qualifier, the process
   receives an error status code when a resource is unavailable.

/SCHEDULE

      /SCHEDULE=3Dabsolute-time

   Places the created process in hibernation and awakens it at the
   specified time.

   Specify the absolute time value according to the rules for
   entering absolute time values given in the VMS DCL Concepts
   Manual.

/SERVICE_FAILURE

      /SERVICE_FAILURE
      /NOSERVICE_FAILURE (default)

   Enables or disables an exception condition notification if an
   error occurs during a system service request. By default, an error
   status code is returned to the process.

   If you specify the /SERVICE_FAILURE qualifier and an error
   occurs during a system service request, the process encounters
   an exception condition.

/SUBPROCESS_LIMIT

      /SUBPROCESS_LIMIT=3Dquota

   Specifies the maximum number of subprocesses that the created
   process is allowed to create.

   The default quota is the quota established at system generation
   time. A process does not require any subprocess quota in order to
   execute. A value of 8 is typical.

   The subprocess limit quota is pooled.

/SWAPPING

      /SWAPPING (default)
      /NOSWAPPING

   Requires PSWAPM (process swap mode) privilege to inhibit process
   swapping.

   Permits the process to be swapped. The default allows a process to
   be swapped from the balance set in physical memory to allow other
   processes to execute.

   With /NOSWAPPING in effect, the process is not swapped out of the
   balance set when it is in a wait state. By default, a process may
   be swapped out of the balance set whenever it is in a wait state.

/TIME_LIMIT

      /TIME_LIMIT=3Dlimit

   Specifies the maximum amount of CPU time (in delta time) a created
   process can use. CPU time is allocated to the created process in
   units of 10 milliseconds. When it has exhausted its CPU time limit
   quota, the created process is deleted.

   If this quota is not specified and the created process is a
   detached process, the detached process receives a default value of
   zero, that is, unlimited CPU time.

   If this quota is not specified and the created process is a
   subprocess, the subprocess receives half the CPU time limit quota
   of the creating process.

   If this quota is specified as zero, the created process has
   unlimited CPU time providing that the creating process also has
   unlimited CPU time. If, however, the creating process does not
   have unlimited CPU time, the created process receives half the CPU
   time limit quota of the creating process.

   The CPU time limit quota is a consumable quota; that is, the
   amount of CPU time used by the created process is not returned
   to the creating process when the created process is deleted.

   If you restrict CPU time for a process, specify the time limit
   according to the rules for specifying delta time values, as given
   in the VMS DCL Concepts Manual.

/UIC

      /UIC=3Duic

   Specifies that the created process be a detached process and
   assigns it a user identification code (UIC). Specify the UIC by
   using standard UIC format as described in the VMS DCL Concepts
   Manual.

/USER

      /USER=3Dusername

   Requires DETACH and CMKRNL (change mode to kernel) privileges
   and, unless you specify /NOAUTHORIZE, read (R) access to the
   user authorization file (UAF).

   Specifies that the created process be a detached process. The
   process runs under the specified username and user identification
   code (UIC). You may supply a different UIC with the /UIC qualifier.

   By default, the username and UIC comes from the requesting process.
   You may specify any username that is validated on your system; if
   you supply /NOAUTHORIZE, you may specify a non-existant username
   as well. The name must be 1 to 12 alphanumeric characters,
   including dollar sign ($) and underscore (_).

/WORKING_SET

      /WORKING_SET=3Ddefault

   Specifies the number of pages in the working set of the created
   process.

   The default working set size is the size established at system
   generation time. The minimum number of pages required for a
   process to execute is 10 pages. The value specified cannot be
   greater than the quota specified with /MAXIMUM_WORKING_SET. A
   value of 200 pages is typical.

   The maximum working set quota is nondeductible.

3  EXAMPLES

   1.$ RUN/PROCESS_NAME=3DSUBA   SCANLINE
     %RUN-S-PROC_ID, identification of created process is 00010044.

     In this example, the RUN command creates a subprocess named
     SUBA to run the image SCANLINE.EXE. The system gives the
     subprocess an identification number of 00010044.

   2.$ RUN/DELAY=3D3:30/OUTPUT=3DBALANCE.OUT BALANCE

     In this example, the RUN command creates a subprocess to run
     the image BALANCE.EXE 3 hours and 30 minutes from now; output
     is written to the file BALANCE.OUT.

   3.$ RUN/INTERVAL=3D1:40/PROCESS_NAME=3DSTAT   STATCHK
     %RUN-S-PROC_ID, identification of created process is 00050023
        .
        .
        .
     $ CANCEL STAT

     In this example, the RUN command creates a subprocess named
     STAT to execute the image STATCHK.EXE. The process is scheduled
     to execute the image at intervals of 1 hour and 40 minutes.
     The process hibernates; however, because neither the /DELAY nor
     the /SCHEDULE qualifier is specified, the first wakeup request
     occurs immediately.

     The CANCEL command subsequently cancels the wakeup requests
     posted by the /INTERVAL qualifier. If the process is currently
     executing the image, it completes the execution and hibernates.

   4.$ RUN/PROCESS_NAME=3DLYRA  LYRA -
     _$/OUTPUT=3D_TTB3: -
     _$/ERROR=3D_TTB3:
     %RUN-S-PROC_ID, identification of created process is 000A002F

     In this example, the RUN command creates a subprocess named
     LYRA to execute the image LYRA.EXE. The /OUTPUT and /ERROR
     qualifiers assign equivalences to the logical names SYS$OUTPUT
     and SYS$ERROR for the subprocess. Any messages the subprocess
     writes to its default output devices are displayed on the
     terminal TTB3.

   5.$ RUN/UIC=3D[100,4]/PRIVILEGES=3D(SAME,NOPSWAPM) -
     _$/NORESOURCE_WAIT   OVERSEER
     %RUN-S-PROC_ID, identification of created process is 0001002C

     In this example, the RUN command creates a detached process
     to execute under the UIC [100,4]. The image OVERSEER.EXE is
     executed. The RUN command gives the process all the privileges
     of the current process, except the ability to alter its swap
     mode. The /NORESOURCE_WAIT qualifier disables resource wait
     mode for the process.

   6.$ DEFINE/GROUP  TEST [MALCOLM.TESTFILES]
     $ RUN/PROCESS=3DSUB  WATCH -
     _$/INPUT=3DTEST:OUT1 -
     _$/OUTPUT=3DF$LOGICAL("SYS$OUTPUT")
     %RUN-S-PROC_ID, identification of created process is 0001002E

     In this example, the DEFINE command creates an entry in the
     group logical name table for the logical name TEST. The RUN
     command creates a subprocess to execute the image WATCH.EXE.

     The /INPUT qualifier defines SYS$INPUT for the subprocesses.
     The logical name TEST defines the directory for the file
     OUT1.DAT. Because the logical name TEST is in the group logical
     name table, the logical name can be translated and referred to
     by the image WATCH.EXE.

     The /OUTPUT qualifier uses the lexical function F$LOGICAL to
     translate the logical name of the current process's SYS$OUTPUT
     device. The equivalence name string is equated to the device
     SYS$OUTPUT for the subprocess.

   7.$ RUN/USER=3DSYSTEM/NOIDENTIFY MY_IMAGE
     $

     In this example, the RUN command creates a detached process
     to execute under username SYSTEM. Since no UIC is specified,
     the UIC of user SYSTEM ([1,4]) is used. The /NOIDENTIFY
     qualifier causes the %RUN-S-PROC_ID message to be suppressed.

=0C---------------------->>> #8: ADV_RUNUSR_V6.HLP <<<-------------------=
---

1  RUN
   Executes an image within the context of your process (see Image).

   Creates a subprocess or a detached process to run an image and
   deletes the process when the image completes execution (see
   Process).
=20

2  Image
   Executes an image within the context of your process. You can
   abbreviate the RUN command to a single letter, R.

   If you specify an image name in the command line with an explicit
   version number (or a semicolon), the image runs with current
   process privileges. If you do not specify an explicit version
   number (or semicolon), the image runs with any privileges with
   which it was installed. If you have DECnet software installed and
   want to execute an image over the network, you must have read (R)
   access to the file.

   Format

     RUN  filespec
=20

3  Parameter
=20

filespec

   Specifies an executable image to be executed. The file type
   defaults to .EXE. The asterisk (*)  and the percent sign (%)
   wildcard characters are not allowed.
=20

3  Qualifier
=20

/DEBUG

      /DEBUG
      /NODEBUG

   Executes the image under control of the debugger. The default
   is the /DEBUG qualifier if the image is linked with the /DEBUG
   qualifier and the /NODEBUG qualifier if the image is linked
   without the /DEBUG qualifier. The /DEBUG qualifier is invalid if
   the image is linked with the /NOTRACEBACK qualifier. The /NODEBUG
   qualifier overrides the effect of the LINK/DEBUG command. If
   the image was linked with the /TRACEBACK qualifier, traceback
   reporting is performed when an error occurs.

   If the image was not linked with the debugger, you can specify
   the /DEBUG qualifier to request the debugger at execution time.
   However, if the /NOTRACEBACK qualifier was specified when the
   image was linked, the /DEBUG qualifier is invalid.

   For a complete description of the OpenVMS Debugger, see the
   OpenVMS Debugger Manual.

   To get help on debugger commands from DCL level, type the
   following command:

   $ HELP/LIBRARY=3DSYS$HELP:DBG$HELP
=20

3  Examples

   1.$ RUN LIBRA

     The image LIBRA.EXE starts executing in the process. If the
     image LIBRA has been installed with amplified privileges, it
     runs with those privileges because you have not explicitly
     specified a version number or a semicolon. Alternatively, the
     image LIBRA.EXE still runs with its amplified privileges, if
     you enter the RUN command as follows:

       $ RUN LIBRA.EXE

   2.$ MACRO/ENABLE=3DDEBUG ORION
     $ LINK/DEBUG ORION
     $ RUN ORION

          VAX DEBUG Version 5.4

     %DEBUG-I-INITIAL, language is MACRO, module set to 'ORION'
     DBG>
        .
        .
        .
     $ RUN/NODEBUG ORION

     A program is compiled, linked, and run with the debugger.
     Subsequently, a RUN/NODEBUG command requests that the debugger,
     which is present in the image, not issue a prompt. If an error
     occurs while the image executes, the debugger can perform
     traceback and report on the error.

   3.$ RUN AQUARIUS.EXE;1

     The image AQUARIUS.EXE starts executing in the process. If
     the image AQUARIUS.EXE has been installed with amplified
     privileges, it does not run with those privileges because you
     have specified a version number. Instead, the image runs with
     current process privileges only. When you specify a version
     number (or even just a semicolon), the image activator does not
     search its list of special images that have been installed with
     privileges. The process AQUARIUS still runs with only normal
     process privileges if you enter the RUN command as follows:

       $ RUN AQUARIUS.EXE;

     In this case, however, the highest version of the image
     AQUARIUS runs.
=20

2  Process
   Creates a subprocess or a detached process to run an image
   and deletes the process when the image completes execution.
   A subprocess is created if any of the qualifiers except /UIC,
   /USER or /DETACHED is specified. A detached process is
   created if the /UIC, /USER or the /DETACHED qualifier is
   specified and you have DETACH user privilege.

   Format

     RUN  filespec
=20

3  Parameter
=20

filespec

   Specifies the file name of an executable image to be executed in
   a separate process. The default file type is .EXE. The asterisk
   (*)  and the percent sign (%) wildcard characters are not allowed
   in the file specification.
=20

3  Qualifiers
=20

/ACCOUNTING

      /ACCOUNTING (default)
      /NOACCOUNTING

   Requires ACNT (accounting) privilege to use the /NOACCOUNTING
   qualifier.

   The /NOACCOUNTING qualifier stops the current accounting file
   tracking the resources used by the created process.

   The /ACCOUNTING qualifier (the default) has no effect.
=20

/AST_LIMIT

      /AST_LIMIT=3Dquota

   Specifies the maximum number of asynchronous system traps (ASTs)
   that the created process can have outstanding.

   If you do specify an AST limit quota, the default quota
   established at system generation time is used. The minimum
   required for any process to execute is 2.

   The AST limit quota is nondeductible.

=20
/AUTHORIZE

      /AUTHORIZE
      /NOAUTHORIZE (default)

   Requires DETACH privilege.

   When the image to be executed is the system login image
   (LOGINOUT.EXE), this qualifier searches the user authorization
   file (UAF) to validate a detached process. The /NOAUTHORIZE
   qualifier creates a detached process that runs under the control
   of the command interpreter.

   When specifying /USER and /AUTHORIZE, the detached process' UIC
   is obtained from the UAF; in this case, a valid username must
   be supplied. Specifying /NOAUTHORIZE causes the new process to
   inherit the UIC from your process; in this case, you may also
   supply a non-existant username.


/BUFFER_LIMIT

      /BUFFER_LIMIT=3Dquota

   Specifies the maximum amount of memory, in bytes, that the
   process can use for buffered I/O operations or for temporary
   mailbox creation.

   If you do not specify a buffered I/O quota, the default value
   established at system generation time is used. The minimum amount
   required for any process to execute is 1024 bytes.

   The buffer limit quota is pooled.
=20

/DELAY

      /DELAY=3Ddelta-time

   Places the created process in hibernation and awakens it after a
   specified time interval.

   Specify the delta time according to the rules for entering delta
   times given in the OpenVMS User's Manual.

   If you specify both the /DELAY and /INTERVAL qualifiers, the
   first wakeup request occurs at the time specified by the /DELAY
   qualifier. All subsequent wakeup requests occur at the interval
   specified by the /INTERVAL qualifier.
=20

/DETACHED

      /DETACHED
      /NODETACHED

   Creates a detached process with the same user identification code
   (UIC) as the current process. (To create a detached process with
   a different UIC, use the /UIC qualifier.) By default, the created
   process is not a detached process.

   By default, the detached process has the same resource quotas as
   the current process; the DETACH privilege allows you to specify
   any quotas you need for the detached process. Unless you have the
   DETACH privilege, the maximum number of detached processes that
   you can create is limited to the quota defined by MAX_DETACH in
   your UAF.
=20

/DUMP

      /DUMP
      /NODUMP (default)

   When an image terminates because of an unhandled error, the /DUMP
   qualifier causes the contents of the address space to be written
   to the file named image-name.DMP in the process's default device
   and directory. You can then use the Analyze/Process_Dump utility
   to analyze the dump.
=20

/ENQUEUE_LIMIT

      /ENQUEUE_LIMIT=3Dquota

   Specifies the maximum number of locks that a process can have
   outstanding at any one time.

   The default quota is that established at system generation time.
   The minimum required for any process to operate is 2.
=20

/ERROR

      /ERROR=3Dfilespec

   Defines an equivalence name string of 1 to 63 alphanumeric
   characters for the logical device name SYS$ERROR. The logical
   name and equivalence name are placed in the process logical name
   table for the created process. (The /ERROR qualifier is ignored
   if you are running SYS$SYSTEM:LOGINOUT.)
=20

/EXTENT

      /EXTENT=3Dquota

   Specifies the maximum size to which the image being executed in
   the process can increase its physical memory size.

   The default quota is that established at system generation time.
   The minimum value required for any process to execute is 10
   pages.

   Specify the value of n as a number of 512-byte pagelets on
   Alpha or 512-byte pages on VAX. Note that the operating system
   rounds up this value to the nearest CPU-specific page so that
   actual amount of physical memory allowed may be larger than the
   specified amount on Alpha.

   The extent quota is nondeductible.
=20

/FILE_LIMIT

      /FILE_LIMIT=3Dquota

   Specifies the maximum number of files that a process can have
   open at any one time.

   The default quota is the quota established at system generation
   time. The minimum amount required for any process to execute is
   2.

   The file limit quota is pooled.
=20

/IDENTIFY

      /IDENTIFY (default)
      /NOIDENTIFY

   Displays the PID (process identification) of the created process.


/INPUT

      /INPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for
   SYS$INPUT. The logical name and equivalence name are placed in
   the process logical name table for the created process.
=20

/INTERVAL

      /INTERVAL=3Ddelta-time

   Requests that the created process be placed in hibernation and be
   awakened at regularly scheduled intervals.

   Specify the delta time according to the rules given in the
   OpenVMS User's Manual.

   If you specify the /DELAY or the /SCHEDULE qualifier with the
   /INTERVAL qualifier, the first wakeup request occurs at the
   time specified by the /DELAY or the /SCHEDULE qualifier; all
   subsequent wakeup requests occur at intervals specified by the
   /INTERVAL qualifier. If you specify neither the /DELAY nor the
   /SCHEDULE qualifier with the /INTERVAL qualifier, the first
   wakeup request occurs immediately by default.
=20

/IO_BUFFERED

      /IO_BUFFERED=3Dquota

   Specifies the maximum number of system-buffered I/O operations
   that the created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2.

   The buffered I/O quota is nondeductible.
=20

/IO_DIRECT

      /IO_DIRECT=3Dquota

   Specifies the maximum number of direct I/O operations that the
   created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2.

   The direct I/O quota is nondeductible.
=20

/JOB_TABLE_QUOTA

      /JOB_TABLE_QUOTA=3Dquota

   Allows you to specify a quota for a detached process's jobwide
   logical name table.

   A value of 0 has a special meaning. It means that the table, for
   all practical purposes, has infinite quota because its quota is
   pooled with that of its parent table, the system directory table.

   Note that the /JOB_TABLE_QUOTA qualifier is relevant only
   for detached processes. If the /JOB_TABLE_QUOTA qualifier is
   specified in a RUN command that results in the creation of a
   subprocess, it is ignored.
=20

/MAILBOX

      /MAILBOX=3Dunit

   Specifies the unit number of a mailbox to receive a termination
   message when the created process is deleted. If no mailbox is
   specified, the creating process receives no notification when the
   subprocess or detached process has been deleted.
=20

/MAXIMUM_WORKING_SET

      /MAXIMUM_WORKING_SET=3Dquota

   Specifies the maximum size (up to 64K pages) to which the image
   being executed in the process can increase its working set size.
   An image can increase its working set size by calling the $ADJWSL
   (Adjust Working Set Limit) system service.

   The default quota is the quota established at system generation
   time. The minimum value required for any process to execute is 10
   pages.

   The maximum working set quota is nondeductible.
=20

/OUTPUT

      /OUTPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for the
   logical device name SYS$OUTPUT. Both the equivalence name and the
   logical name are placed in the process logical name table for the
   created process.
=20

/PAGE_FILE

      /PAGE_FILE=3Dquota

   Specifies the maximum number of pages that can be allocated in
   the paging file for the process. The paging file quota is the
   amount of secondary storage available during execution of the
   image.

   The default quota is the quota established at system generation
   time. The minimum value required for a process to execute is 256
   pages. The paging file quota is pooled.
=20

/PRIORITY

      /PRIORITY=3Dn

   Requires ALTPRI (alter priority) privilege to set the priority
   higher than your current process.

   Specifies the base priority at which the created process
   executes.

   On Alpha, the value of parameter n is a decimal 0 to 63, where 63
   is the highest priority and zero is the lowest. Normal priorities
   range from 0 to 15; real-time priorities range from 16 to 63.

   On VAX, the value of parameter n is a decimal 0 to 31, where 31
   is the highest priority and zero is the lowest. Normal priorities
   range from 0 to 15; real-time priorities range from 16 to 31.

   The default priority is that of the current process.
=20

/PRIVILEGES

      /PRIVILEGES=3D(privilege[,...])

   Requires SETPRV (set privilege) privilege to specify privileges
   that you do not have.

   Defines user privileges for the created process. You can extend
   any privilege you possess to a process you create. By default,
   the created process has the same privileges as its creator. If
   you specify only one privilege, you can omit the parentheses.

   For a list of process privileges, see the OpenVMS Guide to System
   Security.

   You can also use the keyword NOSAME as the privilege parameter.
   If you specify /PRIVILEGES=3DNOSAME, the created process has no
   privileges.
=20

/PROCESS_NAME

      /PROCESS_NAME=3Dprocess-name

   Specifies a name of 1 to 15 characters for the created process.
   The process name is implicitly qualified by the group number of
   the process's user identification code (UIC). By default, the
   name is null.
=20

/QUEUE_LIMIT

      /QUEUE_LIMIT=3Dquota

   Specifies the maximum number of timer queue entries that the
   created process can have outstanding at any one time. This number
   includes timer requests and scheduled wakeup requests.

   The default quota is the quota established at system generation
   time. A process does not require any timer queue quota in order
   to execute.

   The timer queue entry quota is pooled.
=20

/RESOURCE_WAIT

      /RESOURCE_WAIT (default)
      /NORESOURCE_WAIT

   Places the created process in a wait state when a resource
   required for a particular function is not available.

   If you specify the /NORESOURCE_WAIT qualifier, the process
   receives an error status code when a resource is unavailable.
=20

/SCHEDULE

      /SCHEDULE=3Dabsolute-time

   Places the created process in hibernation and awakens it at the
   specified time.

   Specify the absolute time value according to the rules for
   entering absolute time values given in the OpenVMS User's Manual.
=20

/SERVICE_FAILURE

      /SERVICE_FAILURE
      /NOSERVICE_FAILURE (default)

   Enables or disables an exception condition notification if an
   error occurs during a system service request. By default, an
   error status code is returned to the process.

   If you specify the /SERVICE_FAILURE qualifier and an error
   occurs during a system service request, the process encounters
   an exception condition.
=20

/SUBPROCESS_LIMIT

      /SUBPROCESS_LIMIT=3Dquota

   Specifies the maximum number of subprocesses that the created
   process is allowed to create.

   The default quota is the quota established at system generation
   time. A process does not require any subprocess quota in order to
   execute.

   The subprocess limit quota is pooled.
=20

/SWAPPING

      /SWAPPING (default)
      /NOSWAPPING

   Requires PSWAPM (process swap mode) privilege to inhibit process
   swapping.

   Permits the process to be swapped. The default allows a process
   to be swapped from the balance set in physical memory to allow
   other processes to execute.

   With /NOSWAPPING in effect, the process is not swapped out of the
   balance set when it is in a wait state. By default, a process may
   be swapped out of the balance set whenever it is in a wait state.
=20

/TIME_LIMIT

      /TIME_LIMIT=3Dlimit

   Specifies the maximum amount of CPU time (in delta time) a
   created process can use. CPU time is allocated to the created
   process in units of 10 milliseconds. When it has exhausted its
   CPU time limit quota, the created process is deleted.

   If this quota is not specified and the created process is a
   detached process, the detached process receives a default value
   of zero, that is, unlimited CPU time.

   If this quota is not specified and the created process is a
   subprocess, the subprocess receives half the CPU time limit quota
   of the creating process.

   If this quota is specified as zero, the created process has
   unlimited CPU time providing that the creating process also has
   unlimited CPU time. If, however, the creating process does not
   have unlimited CPU time, the created process receives half the
   CPU time limit quota of the creating process.

   The CPU time limit quota is a consumable quota; that is, the
   amount of CPU time used by the created process is not returned to
   the creating process when the created process is deleted.

   If you restrict CPU time for a process, specify the time limit
   according to the rules for specifying delta time values, as given
   in the OpenVMS User's Manual.
=20

/TRUSTED

   Specifies that the created process is part of the Trusted
   Computing Base (TCB) and performs its own auditing. The /DETACH
   qualifier is required as well as the DETACH privilege.
=20

/UIC

      /UIC=3Duic

   Specifies that the created process be a detached process and
   assigns it a user identification code (UIC). Specify the UIC by
   using standard UIC format as described in the OpenVMS Guide to
   System Security.
=20

/USER

      /USER=3Dusername

   Requires DETACH and CMKRNL (change mode to kernel) privileges
   and, unless you specify /NOAUTHORIZE, read (R) access to the
   user authorization file (UAF).

   Specifies that the created process be a detached process. The
   process runs under the specified username and user identification
   code (UIC). You may supply a different UIC with the /UIC qualifier.

   By default, the username and UIC comes from the requesting process.
   You may specify any username that is validated on your system; if
   you supply /NOAUTHORIZE, you may specify a non-existant username
   as well. The name must be 1 to 12 alphanumeric characters,
   including dollar sign ($) and underscore (_).


/WORKING_SET

      /WORKING_SET=3Ddefault

   Specifies the number of pages in the working set of the created
   process.

   The default working set size is the size established at system
   generation time. The minimum number of pages required for a
   process to execute is 10 pages. The value specified cannot be
   greater than the quota specified with /MAXIMUM_WORKING_SET.

   The maximum working set quota is nondeductible.
=20

3  Examples

   1.$ RUN/PROCESS_NAME=3DSUBA   SCANLINE
     %RUN-S-PROC_ID, identification of created process is 00010044.

     In this example, the RUN command creates a subprocess named
     SUBA to run the image SCANLINE.EXE. The system gives the
     subprocess an identification number of 00010044.

   2.$ RUN/DELAY=3D3:30/OUTPUT=3DBALANCE.OUT BALANCE

     In this example, the RUN command creates a subprocess to run
     the image BALANCE.EXE 3 hours and 30 minutes from now; output
     is written to the file BALANCE.OUT.

   3.$ RUN/INTERVAL=3D1:40/PROCESS_NAME=3DSTAT   STATCHK
     %RUN-S-PROC_ID, identification of created process is 00050023
        .
        .
        .
     $ CANCEL STAT

     In this example, the RUN command creates a subprocess named
     STAT to execute the image STATCHK.EXE. The process is scheduled
     to execute the image at intervals of 1 hour and 40 minutes.
     The process hibernates; however, because neither the /DELAY nor
     the /SCHEDULE qualifier is specified, the first wakeup request
     occurs immediately.

     The CANCEL command subsequently cancels the wakeup requests
     posted by the /INTERVAL qualifier. If the process is currently
     executing the image, it completes the execution and hibernates.

   4.$ RUN/PROCESS_NAME=3DLYRA  LYRA -
     _$/OUTPUT=3D_TTB3: -
     _$/ERROR=3D_TTB3:
     %RUN-S-PROC_ID, identification of created process is 000A002F

     In this example, the RUN command creates a subprocess named
     LYRA to execute the image LYRA.EXE. The /OUTPUT and /ERROR
     qualifiers assign equivalences to the logical names SYS$OUTPUT
     and SYS$ERROR for the subprocess. Any messages the subprocess
     writes to its default output devices are displayed on the
     terminal TTB3.

   5.$ RUN/UIC=3D[100,4]/PRIVILEGES=3D(SAME,NOPSWAPM) -
     _$/NORESOURCE_WAIT   OVERSEER
     %RUN-S-PROC_ID, identification of created process is 0001002C

     In this example, the RUN command creates a detached process
     to execute under the UIC [100,4]. The image OVERSEER.EXE is
     executed. The RUN command gives the process all the privileges
     of the current process, except the ability to alter its swap
     mode. The /NORESOURCE_WAIT qualifier disables resource wait
     mode for the process.

   6.$ DEFINE/GROUP  TEST [MALCOLM.TESTFILES]
     $ RUN/PROCESS=3DSUB  WATCH -
     _$/INPUT=3DTEST:OUT1 -
     _$/OUTPUT=3DF$LOGICAL("SYS$OUTPUT")
     %RUN-S-PROC_ID, identification of created process is 0001002E

     In this example, the DEFINE command creates an entry in the
     group logical name table for the logical name TEST. The RUN
     command creates a subprocess to execute the image WATCH.EXE.

     The /INPUT qualifier defines SYS$INPUT for the subprocesses.
     The logical name TEST defines the directory for the file
     OUT1.DAT. Because the logical name TEST is in the group logical
     name table, the logical name can be translated and referred to
     by the image WATCH.EXE.

     The /OUTPUT qualifier uses the lexical function F$LOGICAL to
     translate the logical name of the current process's SYS$OUTPUT
     device. The equivalence name string is equated to the device
     SYS$OUTPUT for the subprocess.

   7.$ RUN/USER=3DSYSTEM/NOIDENTIFY MY_IMAGE
     $

     In this example, the RUN command creates a detached process
     to execute under username SYSTEM. Since no UIC is specified,
     the UIC of user SYSTEM ([1,4]) is used. The /NOIDENTIFY
     qualifier causes the %RUN-S-PROC_ID message to be suppressed.

=0C---------------------->>> #9: ADV_RUNUSR_V7.HLP <<<-------------------=
---

1  RUN
   Executes an image within the context of your process (see Image).

   Creates a subprocess or a detached process to run an image and
   deletes the process when the image completes execution (see
   Process).
=20

2  Image
   Executes an image within the context of your process. You can
   abbreviate the RUN command to a single letter, R.

   If you specify an image name in the command line with an explicit
   version number (or a semicolon), the image runs with current
   process privileges. If you do not specify an explicit version
   number (or semicolon), the image runs with any privileges with
   which it was installed. If you have DECnet software installed and
   want to execute an image over the network, you must have read (R)
   access to the file.

   Format

     RUN  filespec
=20

3  Parameter
=20

filespec

   Specifies an executable image to be executed. The file type
   defaults to .EXE. The asterisk (*)  and the percent sign (%)
   wildcard characters are not allowed.
=20

3  Qualifier
=20

/DEBUG

      /DEBUG
      /NODEBUG

   Executes the image under control of the debugger. The default
   is the /DEBUG qualifier if the image is linked with the /DEBUG
   qualifier and the /NODEBUG qualifier if the image is linked
   without the /DEBUG qualifier. The /DEBUG qualifier is invalid if
   the image is linked with the /NOTRACEBACK qualifier. The /NODEBUG
   qualifier overrides the effect of the LINK/DEBUG command. If
   the image was linked with the /TRACEBACK qualifier, traceback
   reporting is performed when an error occurs.

   If the image was not linked with the debugger, you can specify
   the /DEBUG qualifier to request the debugger at execution time.
   However, if the /NOTRACEBACK qualifier was specified when the
   image was linked, the /DEBUG qualifier is invalid.

   For a complete description of the OpenVMS Debugger, see the
   OpenVMS Debugger Manual.

   To get help on debugger commands from DCL level, type the
   following command:

   $ HELP/LIBRARY=3DSYS$HELP:DBG$HELP
=20

3  Examples

   1.$ RUN LIBRA

     The image LIBRA.EXE starts executing in the process. If the
     image LIBRA has been installed with amplified privileges, it
     runs with those privileges because you have not explicitly
     specified a version number or a semicolon. Alternatively, the
     image LIBRA.EXE still runs with its amplified privileges, if
     you enter the RUN command as follows:

       $ RUN LIBRA.EXE

   2.$ MACRO/ENABLE=3DDEBUG ORION
     $ LINK/DEBUG ORION
     $ RUN ORION

          VAX DEBUG Version 5.4

     %DEBUG-I-INITIAL, language is MACRO, module set to 'ORION'
     DBG>
        .
        .
        .
     $ RUN/NODEBUG ORION

     A program is compiled, linked, and run with the debugger.
     Subsequently, a RUN/NODEBUG command requests that the debugger,
     which is present in the image, not issue a prompt. If an error
     occurs while the image executes, the debugger can perform
     traceback and report on the error.

   3.$ RUN AQUARIUS.EXE;1

     The image AQUARIUS.EXE starts executing in the process. If
     the image AQUARIUS.EXE has been installed with amplified
     privileges, it does not run with those privileges because you
     have specified a version number. Instead, the image runs with
     current process privileges only. When you specify a version
     number (or even just a semicolon), the image activator does not
     search its list of special images that have been installed with
     privileges. The process AQUARIUS still runs with only normal
     process privileges if you enter the RUN command as follows:

       $ RUN AQUARIUS.EXE;

     In this case, however, the highest version of the image
     AQUARIUS runs.
=20

2  Process
   Creates a subprocess or a detached process to run an image
   and deletes the process when the image completes execution.
   A subprocess is created if any of the qualifiers except /UIC,
   /USER or /DETACHED is specified. A detached process is
   created if the /UIC, /USER or the /DETACHED qualifier is
   specified and you have DETACH user privilege.

   Format

     RUN  filespec
=20

3  Parameter
=20

filespec

   Specifies the file name of an executable image to be executed in
   a separate process. The default file type is .EXE. The asterisk
   (*)  and the percent sign (%) wildcard characters are not allowed
   in the file specification.
=20

3  Qualifiers
=20

/ACCOUNTING

      /ACCOUNTING (default)
      /NOACCOUNTING

   Requires ACNT (accounting) privilege to use the /NOACCOUNTING
   qualifier.

   The /NOACCOUNTING qualifier stops the current accounting file
   tracking the resources used by the created process.

   The /ACCOUNTING qualifier (the default) has no effect.
=20

/AST_LIMIT

      /AST_LIMIT=3Dquota

   Specifies the maximum number of asynchronous system traps (ASTs)
   that the created process can have outstanding.

   If you do specify an AST limit quota, the default quota
   established at system generation time is used. The minimum
   required for any process to execute is 2.

   The AST limit quota is nondeductible.
=20

/AUTHORIZE

      /AUTHORIZE
      /NOAUTHORIZE (default)

   Requires DETACH privilege.

   When the image to be executed is the system login image
   (LOGINOUT.EXE), this qualifier searches the user authorization
   file (UAF) to validate a detached process. The /NOAUTHORIZE
   qualifier creates a detached process that runs under the control
   of the command interpreter.

   When specifying /USER and /AUTHORIZE, the detached process' UIC
   is obtained from the UAF; in this case, a valid username must
   be supplied. Specifying /NOAUTHORIZE causes the new process to
   inherit the UIC from your process; in this case, you may also
   supply a non-existant username.


/BUFFER_LIMIT

      /BUFFER_LIMIT=3Dquota

   Specifies the maximum amount of memory, in bytes, that the
   process can use for buffered I/O operations or for temporary
   mailbox creation.

   If you do not specify a buffered I/O quota, the default value
   established at system generation time is used. The minimum amount
   required for any process to execute is 1024 bytes.

   The buffer limit quota is pooled.
=20

/DELAY

      /DELAY=3Ddelta-time

   Places the created process in hibernation and awakens it after a
   specified time interval.

   Specify the delta time according to the rules for entering delta
   times given in the OpenVMS User's Manual or the topic SPECIFY
   Date_Time in online help.

   If you specify both the /DELAY and /INTERVAL qualifiers, the
   first wakeup request occurs at the time specified by the /DELAY
   qualifier. All subsequent wakeup requests occur at the interval
   specified by the /INTERVAL qualifier.
=20

/DETACHED

      /DETACHED
      /NODETACHED

   Creates a detached process with the same user identification code
   (UIC) as the current process. (To create a detached process with
   a different UIC, use the /UIC qualifier.) By default, the created
   process is not a detached process.

   By default, resource quotas for the detached process are limited
   by the quotas of the creator process (maximum) and the system
   parameters PQL_M* (minimum). The DETACH or CMKRNL privilege
   allows you to specify any quotas for the detached process that
   exceed the normal range. Unless you have the DETACH or CMKRNL
   privilege, the maximum number of detached processes that you can
   create is limited to the quota defined by MAX_DETACH in your UAF.
=20

/DUMP

      /DUMP
      /NODUMP (default)

   When an image terminates because of an unhandled error, the /DUMP
   qualifier causes the contents of the address space to be written
   to the file named image-name.DMP in the process's default device
   and directory. You can then use the Analyze/Process_Dump utility
   to analyze the dump.
=20

/ENQUEUE_LIMIT

      /ENQUEUE_LIMIT=3Dquota

   Specifies the maximum number of locks that a process can have
   outstanding at any one time.

   The default quota is that established at system generation time.
   The minimum required for any process to operate is 2.
=20

/ERROR

      /ERROR=3Dfilespec

   Defines an equivalence name string of 1 to 63 alphanumeric
   characters for the logical device name SYS$ERROR. The logical
   name and equivalence name are placed in the process logical name
   table for the created process. (The /ERROR qualifier is ignored
   if you are running SYS$SYSTEM:LOGINOUT.)
=20

/EXTENT

      /EXTENT=3Dquota

   Specifies the maximum size to which the image being executed in
   the process can increase its physical memory size.

   The default quota is that established at system generation time.
   The minimum value required for any process to execute is 10
   pages.

   Specify the value of n as a number of 512-byte pagelets on
   Alpha or 512-byte pages on VAX. Note that the operating system
   rounds up this value to the nearest CPU-specific page so that
   actual amount of physical memory allowed may be larger than the
   specified amount on Alpha.

   The extent quota is nondeductible.
=20

/FILE_LIMIT

      /FILE_LIMIT=3Dquota

   Specifies the maximum number of files that a process can have
   open at any one time.

   The default quota is the quota established at system generation
   time. The minimum amount required for any process to execute is
   2.

   The file limit quota is pooled.
=20

/IDENTIFY

      /IDENTIFY (default)
      /NOIDENTIFY

   Displays the PID (process identification) of the created process.


/INPUT

      /INPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for
   SYS$INPUT. The logical name and equivalence name are placed in
   the process logical name table for the created process.
=20

/INTERVAL

      /INTERVAL=3Ddelta-time

   Requests that the created process be placed in hibernation and be
   awakened at regularly scheduled intervals.

   Specify the delta time according to the rules given in the
   OpenVMS User's Manual or the topic SPECIFY Date_Time in online
   help.

   If you specify the /DELAY or the /SCHEDULE qualifier with the
   /INTERVAL qualifier, the first wakeup request occurs at the
   time specified by the /DELAY or the /SCHEDULE qualifier; all
   subsequent wakeup requests occur at intervals specified by the
   /INTERVAL qualifier. If you specify neither the /DELAY nor the
   /SCHEDULE qualifier with the /INTERVAL qualifier, the first
   wakeup request occurs immediately by default.
=20

/IO_BUFFERED

      /IO_BUFFERED=3Dquota

   Specifies the maximum number of system-buffered I/O operations
   that the created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2.

   The buffered I/O quota is nondeductible.
=20

/IO_DIRECT

      /IO_DIRECT=3Dquota

   Specifies the maximum number of direct I/O operations that the
   created process can have outstanding at any one time.

   The default quota is the quota established at system generation
   time. The minimum required for any process to execute is 2.

   The direct I/O quota is nondeductible.
=20

/JOB_TABLE_QUOTA

      /JOB_TABLE_QUOTA=3Dquota

   Allows you to specify a quota for a detached process's jobwide
   logical name table.

   A value of 0 has a special meaning. It means that the table, for
   all practical purposes, has infinite quota because its quota is
   pooled with that of its parent table, the system directory table.

   Note that the /JOB_TABLE_QUOTA qualifier is relevant only
   for detached processes. If the /JOB_TABLE_QUOTA qualifier is
   specified in a RUN command that results in the creation of a
   subprocess, it is ignored.
=20

/MAILBOX

      /MAILBOX=3Dunit

   Specifies the unit number of a mailbox to receive a termination
   message when the created process is deleted. If no mailbox is
   specified, the creating process receives no notification when the
   subprocess or detached process has been deleted.
=20

/MAXIMUM_WORKING_SET

      /MAXIMUM_WORKING_SET=3Dquota

   Specifies the maximum size (up to 64K pages) to which the image
   being executed in the process can increase its working set size.
   An image can increase its working set size by calling the $ADJWSL
   (Adjust Working Set Limit) system service.

   The default quota is the quota established at system generation
   time. The minimum value required for any process to execute is 10
   pages.

   The maximum working set quota is nondeductible.
=20

/ON

      /ON=3Dnode_name

   Specifies an OpenVMS Cluster node on which a detached process
   is to be created. Quotas are determined by comparing the values
   you specify with the RUN command with the quotas of the creator
   process (maximum) and the PQL_M* system parameters on the target
   node (minimum). To specify quotas outside that range, you must
   have DETACH or CMKRNL privilege. Omitted quota values default to
   the values of the PQL_D* system parameters on the target node.

   The qualifier value node_name is a 1- to 6-character string
   containing the SCS node name of the requested node.

   For example, to create a process named BAR on node FOO that runs
   MY_PROG.EXE, enter the following command:

   $ RUN $10$DKB100:[SMITH]MY_PROG.EXE /DETACH /ON=3D"FOO"/PROCESS_NAME=3D=
"BAR"

   Note that the disk containing the image must be mounted on the
   specified node. Because the disk might not be mounted on the node
   on which the command is entered, the RUN command processor does
   not check whether the image exists. Consequently, the command
   can complete without error even though the created process aborts
   immediately because the image file cannot be found.
=20

/OUTPUT

      /OUTPUT=3Dfilespec

   Defines an equivalence name string of 1 to 63 characters for the
   logical device name SYS$OUTPUT. Both the equivalence name and the
   logical name are placed in the process logical name table for the
   created process.
=20

/PAGE_FILE

      /PAGE_FILE=3Dquota

   Specifies the maximum number of pages that can be allocated in
   the paging file for the process. The paging file quota is the
   amount of secondary storage available during execution of the
   image.

   The default quota is the quota established at system generation
   time. The minimum value required for a process to execute is 256
   pages. The paging file quota is pooled.
=20

/PRIORITY

      /PRIORITY=3Dn

   Requires ALTPRI (alter priority) privilege to set the priority
   higher than your current process.

   Specifies the base priority at which the created process
   executes.

   On Alpha, the value of parameter n is a decimal 0 to 63, where 63
   is the highest priority and zero is the lowest. Normal priorities
   range from 0 to 15; real-time priorities range from 16 to 63.

   On VAX, the value of parameter n is a decimal 0 to 31, where 31
   is the highest priority and zero is the lowest. Normal priorities
   range from 0 to 15; real-time priorities range from 16 to 31.

   The default priority is that of the current process.
=20

/PRIVILEGES

      /PRIVILEGES=3D(privilege[,...])

   Requires SETPRV (set privilege) privilege to specify privileges
   that you do not have.

   Defines user privileges for the created process. You can extend
   any privilege you possess to a process you create. By default,
   the created process has the same privileges as its creator. If
   you specify only one privilege, you can omit the parentheses.

   For a list of process privileges, see the OpenVMS Guide to System
   Security.

   You can also use the keyword NOSAME as the privilege parameter.
   If you specify /PRIVILEGES=3DNOSAME, the created process has no
   privileges.
=20

/PROCESS_NAME

      /PROCESS_NAME=3Dprocess-name

   Specifies a name of 1 to 15 characters for the created process.
   The process name is implicitly qualified by the group number of
   the process's user identification code (UIC). By default, the
   name is null.
=20

/QUEUE_LIMIT

      /QUEUE_LIMIT=3Dquota

   Specifies the maximum number of timer queue entries that the
   created process can have outstanding at any one time. This number
   includes timer requests and scheduled wakeup requests.

   The default quota is the quota established at system generation
   time. A process does not require any timer queue quota in order
   to execute.

   The timer queue entry quota is pooled.
=20

/RESOURCE_WAIT

      /RESOURCE_WAIT (default)
      /NORESOURCE_WAIT

   Places the created process in a wait state when a resource
   required for a particular function is not available.

   If you specify the /NORESOURCE_WAIT qualifier, the process
   receives an error status code when a resource is unavailable.
=20

/SCHEDULE

      /SCHEDULE=3Dabsolute-time

   Places the created process in hibernation and awakens it at the
   specified time.

   Specify the absolute time value according to the rules for
   entering absolute time values given in the OpenVMS User's Manual
   or the topic SELECT DATE_TIME in online help.
=20

/SERVICE_FAILURE

      /SERVICE_FAILURE
      /NOSERVICE_FAILURE (default)

   Enables or disables an exception condition notification if an
   error occurs during a system service request. By default, an
   error status code is returned to the process.

   If you specify the /SERVICE_FAILURE qualifier and an error
   occurs during a system service request, the process encounters
   an exception condition.
=20

/SUBPROCESS_LIMIT

      /SUBPROCESS_LIMIT=3Dquota

   Specifies the maximum number of subprocesses that the created
   process is allowed to create.

   The default quota is the quota established at system generation
   time. A process does not require any subprocess quota in order to
   execute.

   The subprocess limit quota is pooled.
=20

/SWAPPING

      /SWAPPING (default)
      /NOSWAPPING

   Requires PSWAPM (process swap mode) privilege to inhibit process
   swapping.

   Permits the process to be swapped. The default allows a process
   to be swapped from the balance set in physical memory to allow
   other processes to execute.

   With /NOSWAPPING in effect, the process is not swapped out of the
   balance set when it is in a wait state. By default, a process may
   be swapped out of the balance set whenever it is in a wait state.
=20

/TIME_LIMIT

      /TIME_LIMIT=3Dlimit

   Specifies the maximum amount of CPU time (in delta time) a
   created process can use. CPU time is allocated to the created
   process in units of 10 milliseconds. When it has exhausted its
   CPU time limit quota, the created process is deleted.

   If this quota is not specified and the created process is a
   detached process, the detached process receives a default value
   of zero, that is, unlimited CPU time.

   If this quota is not specified and the created process is a
   subprocess, the subprocess receives half the CPU time limit quota
   of the creating process.

   If this quota is specified as zero, the created process has
   unlimited CPU time providing that the creating process also has
   unlimited CPU time. If, however, the creating process does not
   have unlimited CPU time, the created process receives half the
   CPU time limit quota of the creating process.

   The CPU time limit quota is a consumable quota; that is, the
   amount of CPU time used by the created process is not returned to
   the creating process when the created process is deleted.

   If you restrict CPU time for a process, specify the time limit
   according to the rules for specifying delta time values, as given
   in the OpenVMS User's Manual or the topic SPECIFY Date_Time in
   online help.
=20

/TRUSTED

   Specifies that the created process is part of the Trusted
   Computing Base (TCB) and performs its own auditing. The /DETACH
   qualifier is required as well as the DETACH privilege.
=20

/UIC

      /UIC=3Duic

   Specifies that the created process be a detached process and
   assigns it a user identification code (UIC). Specify the UIC by
   using standard UIC format as described in the OpenVMS Guide to
   System Security.
=20

/USER

      /USER=3Dusername

   Requires DETACH and CMKRNL (change mode to kernel) privileges
   and, unless you specify /NOAUTHORIZE, read (R) access to the
   user authorization file (UAF).

   Specifies that the created process be a detached process. The
   process runs under the specified username and user identification
   code (UIC). You may supply a different UIC with the /UIC qualifier.

   By default, the username and UIC comes from the requesting process.
   You may specify any username that is validated on your system; if
   you supply /NOAUTHORIZE, you may specify a non-existant username
   as well. The name must be 1 to 12 alphanumeric characters,
   including dollar sign ($) and underscore (_).


/WORKING_SET

      /WORKING_SET=3Ddefault

   Specifies the number of pages in the working set of the created
   process.

   The default working set size is the size established at system
   generation time. The minimum number of pages required for a
   process to execute is 10 pages. The value specified cannot be
   greater than the quota specified with /MAXIMUM_WORKING_SET.

   The maximum working set quota is nondeductible.
=20

3  Examples

   1.$ RUN/PROCESS_NAME=3DSUBA   SCANLINE
     %RUN-S-PROC_ID, identification of created process is 00010044.

     In this example, the RUN command creates a subprocess named
     SUBA to run the image SCANLINE.EXE. The system gives the
     subprocess an identification number of 00010044.

   2.$ RUN/DELAY=3D3:30/OUTPUT=3DBALANCE.OUT BALANCE

     In this example, the RUN command creates a subprocess to run
     the image BALANCE.EXE 3 hours and 30 minutes from now; output
     is written to the file BALANCE.OUT.

   3.$ RUN/INTERVAL=3D1:40/PROCESS_NAME=3DSTAT   STATCHK
     %RUN-S-PROC_ID, identification of created process is 00050023
        .
        .
        .
     $ CANCEL STAT

     In this example, the RUN command creates a subprocess named
     STAT to execute the image STATCHK.EXE. The process is scheduled
     to execute the image at intervals of 1 hour and 40 minutes.
     The process hibernates; however, because neither the /DELAY nor
     the /SCHEDULE qualifier is specified, the first wakeup request
     occurs immediately.

     The CANCEL command subsequently cancels the wakeup requests
     posted by the /INTERVAL qualifier. If the process is currently
     executing the image, it completes the execution and hibernates.

   4.$ RUN/PROCESS_NAME=3DLYRA  LYRA -
     _$/OUTPUT=3D_TTB3: -
     _$/ERROR=3D_TTB3:
     %RUN-S-PROC_ID, identification of created process is 000A002F

     In this example, the RUN command creates a subprocess named
     LYRA to execute the image LYRA.EXE. The /OUTPUT and /ERROR
     qualifiers assign equivalences to the logical names SYS$OUTPUT
     and SYS$ERROR for the subprocess. Any messages the subprocess
     writes to its default output devices are displayed on the
     terminal TTB3.

   5.$ RUN/UIC=3D[100,4]/PRIVILEGES=3D(SAME,NOPSWAPM) -
     _$/NORESOURCE_WAIT   OVERSEER
     %RUN-S-PROC_ID, identification of created process is 0001002C

     In this example, the RUN command creates a detached process
     to execute under the UIC [100,4]. The image OVERSEER.EXE is
     executed. The RUN command gives the process all the privileges
     of the current process, except the ability to alter its swap
     mode. The /NORESOURCE_WAIT qualifier disables resource wait
     mode for the process.

   6.$ DEFINE/GROUP  TEST [MALCOLM.TESTFILES]
     $ RUN/PROCESS=3DSUB  WATCH -
     _$/INPUT=3DTEST:OUT1 -
     _$/OUTPUT=3DF$LOGICAL("SYS$OUTPUT")
     %RUN-S-PROC_ID, identification of created process is 0001002E

     In this example, the DEFINE command creates an entry in the
     group logical name table for the logical name TEST. The RUN
     command creates a subprocess to execute the image WATCH.EXE.

     The /INPUT qualifier defines SYS$INPUT for the subprocesses.
     The logical name TEST defines the directory for the file
     OUT1.DAT. Because the logical name TEST is in the group logical
     name table, the logical name can be translated and referred to
     by the image WATCH.EXE.

     The /OUTPUT qualifier uses the lexical function F$LOGICAL to
     translate the logical name of the current process's SYS$OUTPUT
     device. The equivalence name string is equated to the device
     SYS$OUTPUT for the subprocess.

   7.$ RUN/USER=3DSYSTEM/NOIDENTIFY MY_IMAGE
     $

     In this example, the RUN command creates a detached process
     to execute under username SYSTEM. Since no UIC is specified,
     the UIC of user SYSTEM ([1,4]) is used. The /NOIDENTIFY
     qualifier causes the %RUN-S-PROC_ID message to be suppressed.

=0C---------------------->>> #10: ADV_RUNUSR_V5.CLD <<<------------------=
----

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
! CLD Definion for VMS V5.
! ------------------------
!
define verb RUN
   synonym R
   synonym RU
   cliroutine RUN, cliflags (abbreviate)
   prefix CLI$K_RUN_
   parameter P1, prompt =3D "File"
      value (required, type =3D $infile)
   qualifier DELAY, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier ERROR, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INTERVAL, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier OUTPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier PRIORITY, syntax =3D RUN_PROCESS
      value (required)
   qualifier PRIVILEGES, syntax =3D RUN_PROCESS
      value (required, list, type =3D PRIVILEGES)
   qualifier PROCESS_NAME, syntax =3D RUN_PROCESS
      value (required)
   qualifier RESOURCE_WAIT, syntax =3D RUN_PROCESS, default
   qualifier SCHEDULE, syntax =3D RUN_PROCESS
      value (required, type =3D $datetime)
   qualifier SERVICE_FAILURE, syntax =3D RUN_PROCESS
   qualifier SWAPPING, syntax =3D RUN_PROCESS, default
   qualifier UIC, syntax =3D RUN_PROCESS
      value (required, type =3D $uic)
   qualifier ACCOUNTING, syntax =3D RUN_PROCESS, default
   qualifier BUFFER_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier TIME_LIMIT, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier FILE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier PAGE_FILE, syntax =3D RUN_PROCESS
      value (required)
   qualifier QUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier SUBPROCESS_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier MAXIMUM_WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier DEBUG
   qualifier AUTHORIZE, syntax =3D RUN_PROCESS
   qualifier MAILBOX, syntax =3D RUN_PROCESS
      value (required)
   qualifier AST_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_BUFFERED, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_DIRECT, syntax =3D RUN_PROCESS
      value (required)
   qualifier ENQUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier EXTENT, syntax =3D RUN_PROCESS
      value (required)
   qualifier DETACHED, syntax =3D RUN_PROCESS, nonnegatable
   qualifier DUMP, syntax =3D RUN_PROCESS
   qualifier JOB_TABLE_QUOTA, syntax =3D RUN_PROCESS
      value (required)
   qualifier USER, syntax =3D RUN_PROCESS
      value (required)
   qualifier IDENTIFY, syntax =3D RUN_PROCESS

define syntax RUN_PROCESS
   image RUNUSR_DIR:ADV_RUNUSR

define type PRIVILEGES
   keyword ACNT, negatable
   keyword ALLSPOOL, negatable
   keyword ALTPRI, negatable
   keyword BUGCHK, negatable
   keyword BYPASS, negatable
   keyword CMEXEC, negatable
   keyword CMKRNL, negatable
   keyword DETACH, negatable
   keyword DIAGNOSE, negatable
   keyword EXQUOTA, negatable
   keyword GROUP, negatable
   keyword GRPNAM, negatable
   keyword GRPPRV, negatable
   keyword LOG_IO, negatable
   keyword MOUNT, negatable
   keyword NETMBX, negatable
   keyword OPER, negatable
   keyword PFNMAP, negatable
   keyword PHY_IO, negatable
   keyword PRMCEB, negatable
   keyword PRMGBL, negatable
   keyword PRMJNL, negatable
   keyword PRMMBX, negatable
   keyword PSWAPM, negatable
   keyword SAME, negatable
   keyword READALL, negatable
   keyword SECURITY, negatable
   keyword SETPRV, negatable
   keyword SHARE, negatable
   keyword SHMEM, negatable
   keyword SYSLCK, negatable
   keyword SYSGBL, negatable
   keyword SYSNAM, negatable
   keyword SYSPRV, negatable
   keyword TMPJNL, negatable
   keyword TMPMBX, negatable
   keyword VOLPRO, negatable
   keyword WORLD, negatable

=0C---------------------->>> #11: ADV_RUNUSR_V6.CLD <<<------------------=
----

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
! CLD Definion for VMS V6.
! ------------------------
!
define verb RUN
   synonym R
   synonym RU
   cliroutine RUN, cliflags (abbreviate)
   prefix CLI$K_RUN_
   parameter P1, prompt =3D "File"
      value (required, type =3D $infile)
   qualifier DELAY, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier ERROR, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INTERVAL, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier OUTPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier PRIORITY, syntax =3D RUN_PROCESS
      value (required)
   qualifier PRIVILEGES, syntax =3D RUN_PROCESS
      value (required, list, type =3D PRIVILEGES)
   qualifier PROCESS_NAME, syntax =3D RUN_PROCESS
      value (required)
   qualifier RESOURCE_WAIT, syntax =3D RUN_PROCESS, default
   qualifier SCHEDULE, syntax =3D RUN_PROCESS
      value (required, type =3D $datetime)
   qualifier SERVICE_FAILURE, syntax =3D RUN_PROCESS
   qualifier SWAPPING, syntax =3D RUN_PROCESS, default
   qualifier UIC, syntax =3D RUN_PROCESS
      value (required, type =3D $uic)
   qualifier ACCOUNTING, syntax =3D RUN_PROCESS, default
   qualifier BUFFER_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier TIME_LIMIT, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier FILE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier PAGE_FILE, syntax =3D RUN_PROCESS
      value (required)
   qualifier QUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier SUBPROCESS_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier MAXIMUM_WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier DEBUG
   qualifier AUTHORIZE, syntax =3D RUN_PROCESS
   qualifier MAILBOX, syntax =3D RUN_PROCESS
      value (required)
   qualifier AST_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_BUFFERED, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_DIRECT, syntax =3D RUN_PROCESS
      value (required)
   qualifier ENQUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier EXTENT, syntax =3D RUN_PROCESS
      value (required)
   qualifier DETACHED, syntax =3D RUN_PROCESS, nonnegatable
   qualifier DUMP, syntax =3D RUN_PROCESS
   qualifier JOB_TABLE_QUOTA, syntax =3D RUN_PROCESS
      value (required)
   qualifier TRUSTED, syntax =3D RUN_PROCESS
   qualifier USER, syntax =3D RUN_PROCESS
      value (required)
   qualifier IDENTIFY, syntax =3D RUN_PROCESS

define syntax RUN_PROCESS
   image RUNUSR_DIR:ADV_RUNUSR

define type PRIVILEGES
   keyword ACNT, negatable
   keyword ALLSPOOL, negatable
   keyword ALTPRI, negatable
   keyword AUDIT, negatable
   keyword BUGCHK, negatable
   keyword BYPASS, negatable
   keyword CMEXEC, negatable
   keyword CMKRNL, negatable
   keyword DETACH, negatable
   keyword DIAGNOSE, negatable
   keyword DOWNGRADE, negatable
   keyword EXQUOTA, negatable
   keyword GROUP, negatable
   keyword GRPNAM, negatable
   keyword GRPPRV, negatable
   keyword IMPORT, negatable
   keyword LOG_IO, negatable
   keyword MOUNT, negatable
   keyword NETMBX, negatable
   keyword OPER, negatable
   keyword PFNMAP, negatable
   keyword PHY_IO, negatable
   keyword PRMCEB, negatable
   keyword PRMGBL, negatable
   keyword PRMJNL, negatable
   keyword PRMMBX, negatable
   keyword PSWAPM, negatable
   keyword SAME, negatable
   keyword READALL, negatable
   keyword SECURITY, negatable
   keyword SETPRV, negatable
   keyword SHARE, negatable
   keyword SHMEM, negatable
   keyword SYSLCK, negatable
   keyword SYSGBL, negatable
   keyword SYSNAM, negatable
   keyword SYSPRV, negatable
   keyword TMPJNL, negatable
   keyword TMPMBX, negatable
   keyword UPGRADE, negatable
   keyword VOLPRO, negatable
   keyword WORLD, negatable

=0C---------------------->>> #12: ADV_RUNUSR_V7.CLD <<<------------------=
----

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
! CLD Definion for VMS V7.
! ------------------------
!
define verb RUN
   synonym R
   synonym RU
   cliroutine RUN, cliflags (abbreviate)
   prefix CLI$K_RUN_
   parameter P1, prompt =3D "File"
      value (required, type =3D $infile)
   qualifier DELAY, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier ERROR, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier INTERVAL, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier OUTPUT, syntax =3D RUN_PROCESS
      value (required, type =3D $outfile)
   qualifier PRIORITY, syntax =3D RUN_PROCESS
      value (required)
   qualifier PRIVILEGES, syntax =3D RUN_PROCESS
      value (required, list, type =3D PRIVILEGES)
   qualifier PROCESS_NAME, syntax =3D RUN_PROCESS
      value (required)
   qualifier RESOURCE_WAIT, syntax =3D RUN_PROCESS, default
   qualifier SCHEDULE, syntax =3D RUN_PROCESS
      value (required, type =3D $datetime)
   qualifier SERVICE_FAILURE, syntax =3D RUN_PROCESS
   qualifier SWAPPING, syntax =3D RUN_PROCESS, default
   qualifier UIC, syntax =3D RUN_PROCESS
      value (required, type =3D $uic)
   qualifier ACCOUNTING, syntax =3D RUN_PROCESS, default
   qualifier BUFFER_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier TIME_LIMIT, syntax =3D RUN_PROCESS
      value (required, type =3D $deltatime)
   qualifier FILE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier PAGE_FILE, syntax =3D RUN_PROCESS
      value (required)
   qualifier QUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier SUBPROCESS_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier MAXIMUM_WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier WORKING_SET, syntax =3D RUN_PROCESS
      value (required)
   qualifier DEBUG
   qualifier AUTHORIZE, syntax =3D RUN_PROCESS
   qualifier MAILBOX, syntax =3D RUN_PROCESS
      value (required)
   qualifier AST_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_BUFFERED, syntax =3D RUN_PROCESS
      value (required)
   qualifier IO_DIRECT, syntax =3D RUN_PROCESS
      value (required)
   qualifier ENQUEUE_LIMIT, syntax =3D RUN_PROCESS
      value (required)
   qualifier EXTENT, syntax =3D RUN_PROCESS
      value (required)
   qualifier DETACHED, syntax =3D RUN_PROCESS, nonnegatable
   qualifier DUMP, syntax =3D RUN_PROCESS
   qualifier JOB_TABLE_QUOTA, syntax =3D RUN_PROCESS
      value (required)
   qualifier TRUSTED, syntax =3D RUN_PROCESS
   qualifier ON, syntax =3D RUN_PROCESS
      value (required)
   qualifier USER, syntax =3D RUN_PROCESS
      value (required)
   qualifier IDENTIFY, syntax =3D RUN_PROCESS

define syntax RUN_PROCESS
   image RUNUSR_DIR:ADV_RUNUSR

define type PRIVILEGES
   keyword ACNT, negatable
   keyword ALLSPOOL, negatable
   keyword ALTPRI, negatable
   keyword AUDIT, negatable
   keyword BUGCHK, negatable
   keyword BYPASS, negatable
   keyword CMEXEC, negatable
   keyword CMKRNL, negatable
   keyword DETACH, negatable
   keyword DIAGNOSE, negatable
   keyword DOWNGRADE, negatable
   keyword EXQUOTA, negatable
   keyword GROUP, negatable
   keyword GRPNAM, negatable
   keyword GRPPRV, negatable
   keyword IMPERSONATE, negatable
   keyword IMPORT, negatable
   keyword LOG_IO, negatable
   keyword MOUNT, negatable
   keyword NETMBX, negatable
   keyword OPER, negatable
   keyword PFNMAP, negatable
   keyword PHY_IO, negatable
   keyword PRMCEB, negatable
   keyword PRMGBL, negatable
   keyword PRMJNL, negatable
   keyword PRMMBX, negatable
   keyword PSWAPM, negatable
   keyword SAME, negatable
   keyword READALL, negatable
   keyword SECURITY, negatable
   keyword SETPRV, negatable
   keyword SHARE, negatable
   keyword SHMEM, negatable
   keyword SYSLCK, negatable
   keyword SYSGBL, negatable
   keyword SYSNAM, negatable
   keyword SYSPRV, negatable
   keyword TMPJNL, negatable
   keyword TMPMBX, negatable
   keyword UPGRADE, negatable
   keyword VOLPRO, negatable
   keyword WORLD, negatable

=0C---------------------->>> #13: ADV_RUNUSR_SETNAM.MAR <<<--------------=
--------

	; ADV_RUNUSR V1.0
	; =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
	;
	; (P) & (C) 1990 by Ing. Ferry Bolh=E1r-Nordenkampf
	; Municipality of Vienna, Municipal departement 14
	; A-1010 Wien (Vienna) - AUSTRIA
	; E-mail: bol@adv.magwien.gv.at
	;
	; All rights reserved.
	;

	; This small kernel mode routine changes the username
	; of the current process to the given string.
	;
	; Arguments:
	;
	; 4(ap) =3D descriptor pointing to new username
	;
	; Returns
	;
	; SS$_NORMAL - username was changed
	;
	; SS$_IVLOGNAM - username too long (max. 12 chars)
	;
	; SS$_NOPRIV - no CMKRNL privilege

	.title	_SETNAM - Change process name

	.ident	"BOL-V1.0/JAN-90"

	.library 'SYS$SHARE:LIB'
	.link	 'SYS$SYSTEM:SYS.STB'/se

	$jibdef
	$pcbdef

	.psect	$$CODE_MAR,shr,exe,nowrt

	.entry	_SETNAM,^m<>
	pushab	(ap)			; Pass argument address
	pushab	K_SETNAM		; and routine address
	calls	#2, @#sys$cmkrnl	; switch to kernel mode
	ret				; Thats all

	.entry	K_SETNAM,^m<r2,r3,r4,r5,r6,r7>
	movab	@#exe$sigtoret,(fp)	; set condition handler
	movq	@4(ap),r6		; r6 =3D length, r7 =3D address
	cmpw	r6,#jib$s_username	; longer than allowed?
	bleq	10$			; no, ok
	movzwl	#ss$_ivlognam,r0	; yes, set status
	ret				; and return

	; Change the username. This must be done twice:
	; in the JIB and in the P1 control space.
	; Unused bytes must be filled up with blanks.
	; R4 contains the address of the PCB.

10$:	movl	pcb$l_jib(r4),r5	; Get JIB address
	movc5	r6,(r7),#^a/ /,#jib$s_username,jib$t_username(r5) ; Change
	movc5	r6,(r7),#^a/ /,#jib$s_username,@#ctl$t_username	  ; username
	movzwl	#ss$_normal,r0		; set status
	ret				; and return
=09
	.end

=0C---------------------->>> #14: ADV_RUNUSR_AXP.OPT <<<-----------------=
-----

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_runusr_axp
adv_runusr_setnam_axp
adv_runusr_msgptr_axp
stack=3D16

=0C---------------------->>> #15: ADV_RUNUSR_VAX_D.OPT <<<---------------=
-------

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_runusr_vax_d
adv_runusr_setnam_vax
adv_runusr_msgptr_vax
sys$system:sys.stb/sele
stack=3D16

=0C---------------------->>> #16: ADV_RUNUSR_VAX_V.OPT <<<---------------=
-------

!
! ADV_RUNUSR V1.0
! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
!
! (P) & (C) 1995 by Ing. Ferry Bolh=E1r-Nordenkampf
! Municipality of Vienna, Municipal departement 14
! A-1010 Wien (Vienna) - AUSTRIA
! E-mail: bol@adv.magwien.gv.at
!
! All rights reserved.
!
adv_runusr_vax_v
adv_runusr_setnam_vax
adv_runusr_msgptr_vax
sys$share:vaxcrtl/shar
sys$system:sys.stb/sele
stack=3D16

----------------------->>> END OF MAIL <<<----------------------


--------------15FB59E21CFB
Content-Type: text/plain; charset=iso-8859-1; name="chklgi010.mai"
Content-Disposition: inline; filename="chklgi010.mai"
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by marmeladinger.adv.magwien.gv.at id MAA01422


	CHKLGI V1.0
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D


	This mail contains the following files (in this order):

	$$$README.DOC		General information how to use and build
				CHKLGI. As its name indicates, read this
				file before installing and using CHKLGI.
				Please ignore the information concerning
				saveset processing.

	$$$CHKLGI.DOC		A documentation about the CHKLGI routine,
				describing its arguments, behaviour and
				restrictions.

	BUILD_OLB.COM		A command procedure to build the OLB (object
				library) wherein CHKLGI resides. A VAXC or
				DECC compiler is required.

	BUILD_LOGIN.COM		A command procedure to build LOGIN.EXE, a
				small test program which allows you to test
				CHKLGI and to perform 'spurious' logins.

	BUILD_DEF_AND_LIB.COM	A command procedure to build include files
				and text libraries for various languages.

	*.C			C-sources of CHKLGI (11 files). See therein
				for more description about their contents.

	*.H			Includes (4 files). Same as above.

	_CHKQUO.MAR		A small kernel-mode routine to obtain login
				quotas.

	_NAM_2_ADD.MAR		A small macro routine to translate a nodename
				into a node address.

	(Total of 22 files.)

	You need a VAX C or DEC C compiler to build CHKLGI.

	All files are separated with a header line containing a
	form feed (ASCII 12) character.

	After extracting all files from this mail in a directory,
	go to this directory and type @BUILD_OLB.


	Hope you'll find it useful. Have fun with CHKLGI!

                                        Greetings, Ferry


=0C---------------------->>> #1: $$$README.DOC <<<----------------------



	$$$README.DOC
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	CHKLGI V1.0
	-----------

	This file contains general information about building and
	usage of the CHKLGI (check login) routine. See $$$CHKLGI.DOC
	for a detailled description of the arguments and behaviour.

	CHKLGI is a routine which allows you to perform the same
	checks and tasks as LOGINOUT.EXE (the system's login image)
	when a new process is logged in. You may check for correct
	passwords, login restrictions, perform ALF (automatic login
	facility) and proxy-related operations, update the intrusion
	database and perform system auditing of your logins.

	CHKLGI shows the use of many less-known system services like
	SYS$AUDIT_EVENT, SYS$SCAN_INTRUSION, SYS$VERIFY_PROXY, as
	well as the undocumented image activation service SYS$IMGACT
	and the license-related services SYS$GRANT_LICENSE, SYS$LOOKUP_
	LICENSE and SYS$RELEASE_LICENSE. It also shows how to use
	item lists in C (for SYS$GETUAI) and some other useful
	techniques. Finally, the MACRO-32 program, which runs in
	kernel mode, shows how to scan the PCB (process control
	block) vector array and how to extract information from
	these and related data structures.
=0C=09

	1) Software requirements
	------------------------

	CHKLGI was compiled and tested on the following VMS
	and C compiler versions:

	Alpha:	OpenVMS V6.2	DEC C V5.5-002
		OpenVMS V7.1	DEC C V5.5-002

	VAX:	VAX/VMS V5.4	VAX C V3.1-051
		VAX/VMS V6.1	VAX C V3.2-044
		OpenVMS V6.2	DEC C V5.2-003
		OpenVMS V7.1	DEC C V5.5-002

	You may try to compile it on older versions as well,
	but i don't know whether it will run there without
	problems (i havn't other versions available).

	The following VMS versions are required for intrusion
	processing, event auditing and proxy processing:

	Alpha:	OpenVMS V6.2 or higher
	VAX:	VAX/VMS V6.1 or higher

	The reason for this is that the approbiate system
	services doesn't exist in earlier VMS versions.
=0C

	2) Contents of Saveset
	----------------------

	CHKLGI is distributed as saveset, CHKLGI.SAV. Copy the
	saveset into an empty directory and type

	$ BACKUP CHKLGI010.SAV/SAVE []

	This will extract the saveset and create the following
	files:

	$$$README.DOC	This file.

	$$$CHKLGI.DOC	A detailled description of CHKLGI.

	*.C		C-sources of CHKLGI (11 files). See therein
			for more description about their contents.

	*.H		Includes (4 files). Same as above.

	_CHKQUO.MAR	A small kernel-mode routine to obtain login
			quotas.

	_NAM_2_ADD.MAR	A small macro routine to translate a nodename
			into a node address.

	BUILD_DEF_AND_LIB.COM	A command procedure to built
			include files and text libraries for various
			languages.

	BUILD_OLB.COM	A command procedure to build the OLB (object
			library) wherein CHKLGI resides. A VAXC or
			DECC compiler is required.

	BUILD_LOGIN.COM	A command procedure to build LOGIN.EXE, a
			small test program which allows you to test
			CHKLGI and to perform 'spurious' logins.

	CHKLGI_AXP.OLB	The CHKLGI OLB for use on Alpha.

	CHKLGI_VAX_DECC.OLB   The CHKLGI OLB for use on VAX with the
			DECC$SHR RTL (DEC C run-time environment).

	CHKLGI_VAX_VAXC.OLB   The CHKLGI OLB for use on VAX with the
			VAXCRTL (VAX C run-time environment).

	LOGIN_AXP.OBJ	The LOGIN object to build LOGIN.EXE on Alpha.

	LOGIN_VAX_DECC.OBJ   The LOGIN object to build LOGIN.EXE on
			VAX with the DEC C run-time environment

	LOGIN_VAX_VAXC.OBJ   The LOGIN object to build LOGIN.EXE on
			VAX with the VAX C run-time environment

	There are total of 28 files occupying 925 disk blocks.
=0C

	3) Building the object library
	------------------------------

	Although the object library is included in the distribution
	kit and is ready for use, you may want to rebuild it. You
	need a DEC C compiler (Alpha) and a DEC C and/or VAX C
	compiler (VAX) for this.

	On Alpha, type:

	$ @BUILD_OLB

	On VAX, type:

	$ @BUILD_OLB VAXC	to build the VAX C version, and

	$ @BUILD_OLB DECC	to build the DEC C version.

	in the directory where the saveset was extracted.

	On VAX, if you omit the parameter, both OLB's are built
	if both compilers are installed. If one C compiler is
	installed only, the approbiate library is built.

	The procedure displays every command line it executes.

	After the build is complete, you should copy the object
	library/libraries to SYS$COMMON:[SYSLIB] so that the
	linker can easily find them. You need SYSPRV for this.
=0C

	4) Building LOGIN.EXE
	---------------------

	The distribution kit includes the objects of a small
	test tool called LOGIN. It allows you to call CHKLGI
	and to see what happens when different arguments are
	passed to it.

	To build the tool, type

	$ @BUILD_LOGIN

	in the directory where the saveset was extracted.

	On VAX, if both OLBs were created, you may supply
	"VAXC" as parameter. This forces the creation of the
	VAXC version; otherwise, DEC C is selected as default.
	If the DEC C OLB wasn't created, VAX C is selected
	automatically.

	Since CHKLGI requires CMKRNL, SYSPRV, AUDIT and
	SECURITY privileges, your process must have this
	privileges as well in order to run LOGIN.

	Upon completion, type LOGIN ? to get a help text.=09
=0C

	5) Calling CHKLGI
	-----------------


	5a) Calling CHKLGI from C
	- - - - - - - - - - - - -

	CHKLGI provides its own symbol definition file, CHKLGIDEF.H.
	You may copy this file to SYS$COMMON:[SYSLIB] or wherever
	you tell your C compiler to look for include files. The
	other .H files from the distribution kit aren't required=20
	here; they are required only if you want to rebuild the
	object library (see chapter 3).

	See LOGIN.C for an example how to call CHKLGI from a C
	program.



	5b) Calling CHKLGI from other languages
	- - - - - - - - - - - - - - - - - - - -

	The distribution kit provides a procedure which allows
	you to generate language-specific definition files and
	text libraries from the C include file, CHKLGIDEF.H.
	The following languages are supported:

	BASIC, BLISS, COBOL, DIBOL, FORTRAN, MACRO, PLI and PASCAL.

	To create the definition files and the library for a
	specific language, type this:

	$ @BUILD_DEF_AND_LIB <lang>

	where <lang> is the name of your favorite language, as
	listed above.

	Depending on the selected language, the procedure creates
	the following files, libraries and modules:

	Language    File(s)	     Library            Module(s)
	-----------------------------------------------------------
	BASIC	    $CHKLGIDEF.BAS,  BASIC$CHKLGI.TLB   $CHKLGIDEF,
		    CHKLGI$RTN.BAS                      CHKLGI$RTN
	-----------------------------------------------------------
	BLISS	    $CHKLGIDEF.B32   -                  -
		    CHKLGI$RTN.B32
	-----------------------------------------------------------
	COBOL	    $CHKLGIDEF.COB   -                  -
	-----------------------------------------------------------
	DIBOL       $CHKLGIDEF.DBL   -                  -
	-----------------------------------------------------------
	FORTRAN	    $CHKLGIDEF.FOR   -                  -
	-----------------------------------------------------------
	MACRO	    $CHKLGIDEF.MAR   CHKLGI.MLB         $CHKLGIDEF
	-----------------------------------------------------------
	PASCAL	    $CHKLGIDEF.PAS   PAS$CHKLGI.TLB	$CHKLGIDEF,
		    CHKLGI$RTN.PAS			CHKLGI$RTN
	-----------------------------------------------------------
	PLI	    $CHKLGIDEF.PLI,  PLI$CHKLGI.TLB     $CHKLGIDEF,
		    CHKLGI$RTN.PLI                      CHKLGI$RTN
	-----------------------------------------------------------

	The file/module $CHKLGIDEF contains symbolic constants and
	literals. This module must be included whenever these
	constants are used, for example, if you specify the 'flags'
	and/or 'itmlst' arguments to CHKLGI.

	Where approbiate, the file/module CHKLGI$RTN contains a
	formal (prototype) definition of the CHKLGI routine. This
	definition allows the compilers to ensure that the correct
	arguments were passed with the correct passing mechanism.

	After the build is complete, you should copy the resultant
	files and libraries to SYS$COMMON:[SYSLIB] so that the
	compilers can easily find them. You need SYSPRV for this.

	If you include the above modules, you must specify the
	library when invoking the compiler. For example:

	$ PLI <prog>+SYS$SHARE:CHKLGI/LIBRARY

	Most compilers accept a text library specification with
	the /LIBRARY qualifier. See the description of your
	compiler how to include modules from text libraries.

	Please note:

	We have compilers for the following languages only: C,
	MACRO and PLI. We haven't other compilers and i don't
	know about other languages. For these languages, i looked
	at the approbiate language references only to find out the
	syntax for literal definitions and prototype declarations.
	I couldn't check whether the generated include files will
	actually work.

	If you're using another language and encounter problems
	with the generated includes, my apologies in advance. If
	you've corrected the error(s) in the files, i would really
	appreciate if you tell me the corrections. I'll include
	them in my sources as well and will redistribute the
	corrected kit.

	If you're using a language which is not currently included
	in BUILD_DEF_AND_LIB.COM, let me know which one and the
	syntax for function declarations and literal definitions.
	I'll include it into the procedure as well.
=0C

	6) Linking programs with CHKLGI
	-------------------------------

	To link your program which CHKLGI, you must specify the
	object library with the /LIBRARY qualifier in the linkers
	command line.

	Note this:

	CHKLGI accesses executive data cells and system data
	structures. One side-effect of this is that the resultant
	image has VMS version-dependencies; it can't be used on
	older VMS versions and on Alpha, in most cases, on newer
	as well. In general, you should relink your program when
	you change (upgrade) the VMS version. This is especially
	important on Alpha when upgrading from VMS V6.1 or V6.2
 	(32 bit system) to VMS V7.0 or V7.1 (64 bit system).

	The system components with a dependency are:

		SYS$K_SYSGEN
		SYS$K_MISC
		SYS$K_PROCESS_SCHED
		SYS$K_STABLE		(Alpha only)

	Remember that CHKLGI requires CMKRNL, SYSPRV, AUDIT and
	SECURITY privileges and therefore every program which
	calls CHKLGI requires these privileges as well. In order
	to make a program (which uses CHKLGI) available to non-
	privileged users, you must install the program with the
	above privileges.



	6a) Linking on Alpha
	--------------------

	On Alpha, you must specify /SYSEXE to include the system
	base image, SYS$LOADABLE_IMAGES:SYS$BASE_IMAGE.EXE:

	$ LINK/SYSEXE=3DSELECT <prog>,SYS$SHARE:CHKLGI_AXP/LIBRARY

	This assumes that the object library was copied to
	SYS$SHARE.



	6b) Linking on VAX
	------------------

	On VAX, you must link your image with one of the two
	provided CHKLGI object libraries:

	CHKLGI_VAX_DECC.OLB - uses the DEC C RTL (DECC$SHR.EXE)
	CHKLGI_VAX_VAXC.OLB - uses the VAX C RTL (VAXCRTL.EXE).

	The reason for providing two object libraries is simple:
	within the same image, only the DECC$SHR OR the VAXCRTL
	may be used. An image should NOT be linked against both
	run-time libraries since the environments established by
	them will affect each other.
=09
	In general, if you use a language other than VAX C, you
	should use CHKLGI_VAX_DECC.OLB, the object library for
	the newer DEC C environment. If your main program was
	compiled with DEC C, you MUST use this library. Note
	that you must run VMS V6.0 or higher or must have the
	AACRT060 DEC C run-time kit installed (on V5.5, V5.5-1
	and V5.5-2).

	You MUST use the VAX C OLB in the following cases:

	o) Your program was written in VAX C.

	o) You are running VMS V5.4-3 or earlier.

	o) You are running VMS V5.5, V5.5-1 or V5.5-2 and
	   have not the DEC C run-time kit installed.

	o) You are linking your image against one or more
	   shareable images which are, in their part, linked
	   against VAXCRTL.

	On good example for problems which may occur is the
	run-time library provided with UCX for socket calls,
	UCX$IPC_SHR.EXE: it was linked against VAXCRTL until
	UCX V4.0 - now, starting with UCX V4.1, it is linked
	against DECC$SHR.

	If you're not sure whether you use shareable images
	which are linked against VAXCRTL, link your image with
	the DEC C OLB and perform an ANALYZE/IMAGE/OUT=3DX.X,
	followed by a SEARCH X.X VAXCRTL. If this string is
	found, VAXCRTL is used and you must use the VAX C OLB.

	Since CHKLGI accesses privileged data structures, you
	must include SYS$SYSTEM:SYS.STB, the system symbol
	table file, in the link. In addition, if you use VAX C,
	you must specify the VAX C RTL (using an option file).

	The following example shows how to link your program
	with the DEC C OLB:

	$ LINK <prog>,-
	_$ SYS$SHARE:CHKLGI_VAX_DECC/LIBRARY,-
	_$ SYS$SYSTEM:SYS.STB/SELECT
	$

	The following example shows how to link your program
	with the VAX C OLB:

	$ LINK <prog>,SYS$INPUT/OPTIONS
	SYS$SHARE:CHKLGI_VAX_VAXC/LIBRARY
	SYS$SHARE:VAXCRTL/SHARE
	SYS$SYSTEM:SYS.STB/SELECT
	^Z
	$

	This assumes that the object libraries were copied to
	SYS$SHARE.
=0C

	7) Final notes
	--------------

	Please note first the following:

	"This software is COPYRIGHT =A9 1995-1997, Municipality of
	 City of Vienna. ALL RIGHTS RESERVED.

	 Permission is granted for non-profit redistribution and use,
	 provided that no changes are made in the sources and that
	 this copyright notice remains intact.

	 This software is provided "AS IS". The author, Ing. Ferry
	 Bolhar (bol@adv.magwien.gv.at) makes no representations or
	 warranties with respect to the software."

	CHKLGI was initial part of a server program which declared a
	network object and performed authorization of all incoming
	requests by validating the username, the password (if given)
	and the account flag DISABLED in the target user's UAF record.
	No further checks were made in the original version.

	Later, support was added to check login times/days as well,
	and to log invalid requests in a logfile.

	Finally, with VMS V6.1, support for proxies and intrusion
	processing was provided and invalid requests are now logged
	by the standard VMS alarm/audit system.

	So it wasn't too difficult to enhance CHKLGI to perform all
	other login checks as well, to place it into an object
	library and make it available for general use.

	People frequently ask in VMS newsgroups for a general-purpose
	login validation routine - well, CHKLGI should suit all
	requirements!

	If you have any questions, corrections, enhancements, please
	contact me: bol@adv.magwien.gv.at.

	Ing. Ferry Bolhar

	Vienna, May 1997

=0C---------------------->>> #2: $$$CHKLGI.DOC <<<----------------------



	$$$CHKLGI.DOC
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	CHKLGI V1.0
	-----------

	This file contains a detailled description of the login check
	routine CHKLGI. This routine is provided as ojbect library:

	SYS$SHARE:CHKLGI_AXP.OLB (Alpha)
	SYS$SHARE:CHKLGI_VAX_VAXC.OLB (VAX, VAX C)
	SYS$SHARE:CHKLGI_VAX_DECC.OLB (VAX, DEC C)

	See the file $$$README.DOC how to build and use these
	libraries.
=0C

	CHKLGI - Perform login checks
	-----------------------------

	Checks whether a user may login according its account in the
	UAF (user authorization file) and user-supplied criterias.

	Format:

	CHKLGI [usrnam], [lgidev], [reminf], [paswd1], [paswd2], [lgityp],
	       [lgitim], [lgiday], [flags], [initmlst], [outitmlist]

	C Prototype:

	typedef struct dsc$descriptor_s dsc;

	int chklgi (dsc *usrnam, dsc *lgidev, dsc *reminf, dsc *paswd1,
		    dsc *paswd2, int *lgityp, int *lgitim, int* lgiday,
		    void *flags, void *initmlst, void *outitmlst);


	Arguments:
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	usrnam
	------

	OpenVMS usage: char_string
	Type:          character-coded text string
	Access:        read only
	Mechanism:     by descriptor - fixed-length string descriptor

	Name of the user for which the login check should occur. The
	'usrnam' argument is the address of a descriptor pointing to
	a character text string containing the user name. The user-
	name string can contain a maximum of 12 alphanumeric
	characters, including dollar sign ($) and underscore (_).

	The specified user must exist in the UAF. Note that the string
	"DEFAULT" is reserved by the AUTHORIZE utility. If you specify
	this string, LGI$_NOSUCHUSER is returned immediately.

	Depending on the login type, this argument is required or
	optional. See the description section.



	lgidev
	------

	OpenVMS usage: char_string
	Type:          character-coded text string
	Access:        read only
	Mechanism:     by descriptor - fixed-length string descriptor

	Name of the login device (terminal) from which the login
	occurs. The 'lgidev' argument is the address of a descriptor
	pointing to a character text string containing the login device
	name or a logical name pointing to it. The string can contain
	a maximum of 63 alphanumeric characters, including dollar sign
	($) and underscore (_).

	The specified/resultant device must exist and must have a
	device class of DC$_TERM (terminal) or DC$_WORKSTATION (DEC-
	windows workstation device), otherwise the status LGI$_INVINPUT
	is returned. Note that this check is skipped for detached
	logins where the login device may be a mailbox as well.

	If the specified terminal is set to /MODEM, it must have
	the "Remote" characteristic set as well, otherwise the status
	LGI$_NOTMODEM is returned.

	This argument is optional. See the description section for
	more information.



	reminf
	------

	OpenVMS usage: char_string
	Type:          character-coded text string
	Access:        read only
	Mechanism:     by descriptor - fixed-length string descriptor

	Remote information about the login source. The 'reminf'
	argument is the address of a descriptor pointing to a character
	text string in the format "REMNOD::REMUSR". The string can
	contain a maximum of 63 characters.

	This argument is optional. See the description section for more
	information.



	paswd1
	------

	OpenVMS usage: char_string
	Type:          character-coded text string
	Access:        read only
	Mechanism:     by descriptor - fixed-length string descriptor

	Primary password. The 'paswd1' argument is the address of a
	descriptor pointing to a character text string containing the
	primary login password. The string can contain a maximum of 32
	alphanumeric characters, including dollar sign ($) and under-
	score (_). Lowercase characters are converted to uppercase.

	This argument is optional. If supplied, the given password is
	validated against the hashed primary password stored in the
	target user's account (UAF record).



	paswd2
	------

	OpenVMS usage: char_string
	Type:          character-coded text string
	Access:        read only
	Mechanism:     by descriptor - fixed-length string descriptor

	Secondary password. The 'paswd2' argument is the address of a
	descriptor pointing to a character text string containing the
	secondary login password. The string can contain a maximum of
	32 alphanumeric characters, including dollar sign ($) and
	underscore (_). Lowercase characters are converted to uppercase.

	This argument is optional. If supplied, the given password is
	validated against the hashed secondary password stored in the
	target user's account.



	lgityp
	------

	OpenVMS usage: longword_unsigned
	Type:          longword (unsigned)
	Access:        read only
	Mechanism:     by reference

	Login type (source of login). The 'lgityp' argument is the
	address of a longword containing the type of the login.

	The following login types are defined and are considered as
	non-interactive logins (process-permanent file SYS$COMMAND
	is not a terminal device):

	CHKLGI$_DETACHED:	Detached login
	CHKLGI$_NETWORK:	Network job login
	CHKLGI$_BATCH:		Batch job login

	The following login types are defined and are considered as
	interactive logins (process-permanent file SYS$COMMAND is
	a terminal device):

	CHKLGI$_LOCAL:		Local login (serial line or LAT)
	CHKLGI$_DIALUP:		Login via modem over telephone line
	CHKLGI$_REMOTE:		Remote login (via DECnet or TCP/IP)
	CHKLGI$_DECWINDOWS:	DECwindows login on a workstation

	Different checks are made depending on the given source.
	See the description section.

	The symbol names are defined in the $CHKLGIDEF module.

	This argument is optional. If you omit it, it defaults to
	CHKLGI$_LOCAL.



	lgitim
	------

	OpenVMS usage: date_time
	Type:          quadword
	Access:        read only
	Mechanism:     by reference

	Login time. The 'lgitim' argument is the address of a quad-
	word containing the binary time at which the login should
	occur. A positive time value specifies an absolute time at
	which the login occurs; a negative time value specifies an
	offset (delta time) from the current time.

	This argument is optional. If you omit it, the current
	time is substituted. See the description section for more
	information.



	lgiday
	------

	OpenVMS usage: longword_unsigned
	Type:          longword (unsigned)
	Access:        read only
	Mechanism:     by reference

	Login day. The 'lgiday' argument is the address of a longword
	containing the day of the login (where Monday=3D0...Sunday=3D6).

	This argument is optional. If you omit it, the day is computed
	from the time given in the 'lgitim' argument. If you omit both
	'lgiday' and 'lgitim', the day is computed from the system
	time. See the description section for more information.



	flags
	-----

	OpenVMS usage: mask_longword
	Type:          longword (unsigned)
	Access:        read only
	Mechanism:     by reference

	Flags affecting the behaviour of CHKLGI. The 'flags' argument
	is a longword pointing to a longword bit vector wherein each
	bit corresponds to a flag. The $LGICHKDEF module defines a
	symbolic name for each bit. You construct the flags argument
	by performing a logical OR operation on the symbol names for
	all desired flags. The following flags are defined:

	CHKLGI$M_SKP_ALOGIN_CHK - when you set this flag, CHKLGI
		does not check whether the given account name can
		be used for auto-logins only.

	CHKLGI$M_SKP_DAY_CHK - when you set this flag, CHKLGI
		does not check for correct login day (bypass daily
		restrictions).

	CHKLGI$M_SKP_DISACC_CHK - when you set this flag, CHKLGI
		does not check whether the user's account is disabled.

	CHKLGI$M_SKP_DWICAP_CHK - when you set this flag, CHKLGI
		does not check whether the given account can be
		used for DECwindows logins.

	CHKLGI$M_SKP_EXPACC_CHK - when you set this flag, CKKLGI
		does not check whether the user's account has expired.

	CHKLGI$M_SKP_EXPPWD_CHK - when you set this flag, CHKLGI
		does not check whether the primary and/or secondary
		password has expired.

	CHKLGI$M_SKP_HOUR_CHK - when you set this flag, CHKLGI
		does not check for correct login time (bypass hourly
		restrictions).

	CHKLGI$M_SKP_LGIDIS_CHK - when you set this flag, CHKLGI
		does not check whether logins are currently disabled.

	CHKLGI$M_SKP_LIC_CHK - when you set this flag, CHKLGI
		does not perform license-related checks.

	CHKLGI$M_SKP_MAXACC_CHK - when you set this flag, CHKLGI
		does not check whether the processes/account quota
		has exceeded.

	CHKLGI$M_SKP_MAXINT_CHK - when you set this flag, CHKLGI
		does not check whether the system-wide interactive
		login quota has exceeded.

	CHKLGI$M_SKP_MAXUSR_CHK - when you set this flag, CHKLGI
		does not check whether the processes/username quota
		has exceeded.

	CHKLGI$M_SKP_SRC_CHK - when you set this flag, CHKLGI
		does not check whether the user can login from the
		given login source.

	CHKLGI$M_DO_CLI_CHK - when you set this flag, CHKLGI checks
		whether the CLI and CLITABLES specified in the UAF
		record may be activated as known, shareable images.
		This check is normally bypassed.

		The images are activated in P1 space.

		Note that specifying this flag results in an image
		activation of both, CLI and CLITABLES images in the
		context of your program. This may result in un-
		expected behaviour. In addition, the process' working
		set may increase. You should set this flag only if
		you require it absolutly.

	CHKLGI$M_INTRUSION - when you set this flag, CHKLGI uses
		the system intrusion database to check whether
		breakin-evasion is in progress and updates the
	        intrusion database in the case of login failures.
		To set this flag, you must run VAX/VMS V6.1 or
		higher or OpenVMS Alpha V6.2 or higher. In addition,
		SECURITY privilege is required.

	CHKLGI$M_NO_AUDIT - when you set this flag, CHKLGI does not
		send the login event to the alarm/audit system (no
		auditing is done). Setting this flag requires SECURITY
		privilege.

		Note that auditing is supported on VAX/VMS V6.0
		and higher only and on OpenVMS Alpha V6.1 and
		higher only.

	CHKLGI$M_UPDATE_UAF - when you set this flag, CHKLGI updates
		the 'last login' or 'login failures' fields in the
		target user's account. To use this flag, you must
		run VAX/VMS V6.0 or higher or OpenVMS Alpha V6.1 or
		higher.

	See the description section for more information about the
	various checks performed by CHKLGI.

	This argument is optional. If you omit it, all flags are
	disabled.



	initmlst
	--------

	OpenVMS usage:  item_list_3
	Type:           longword (unsigned)
	Access:         read only
	Mechanism:      by reference

	Item list simulating qualifiers which may be specified with
	the username in response to the "Username:" prompt. The
	'initmlst' argument is the address of a list of one or more
	item descriptors, each of which specifies an item code. The
	item list is terminated by an item code value of 0 or by a
	longword value of 0. Note that the 'return length' fields of
	the item descriptors are not used and should be set to 0 as
	well.

	The following item code values are defined:

	CHKLGI$_CLI:	when specified, simulates that the /CLI=3D<name>
			qualifier was supplied. This is not allowed
			for accounts with the RESTRICTED, CAPTIVE or
			DEFCLI flags set.

			The 'value' field of the item descriptor
			contains the address of a string containing
			the CLI name; the 'length' field contains the
			length of this string. The string must not
			exceed 39 characters and must contain the file
			name only; the specified string is completed
			with "SYS$SYSTEM:.EXE". If the CHKLGI$M_DO_
			CLI_CHK flag is set, an attempt is made to
			activate this CLI.

			The default is the CLI specified in the target
			user's account; if no CLI was specified therein,
			it is "DCL".

	CHKLGI$_TABLES:	when specified, simulates that the /TABLES=3D<name>
			qualifier was supplied. This is not allowed for
			accounts with the RESTRICTED, CAPTIVE or DEFCLI
			flags set.

			The 'value' field of the item descriptor
			contains the address of a string containing
			the CLI table name; the 'length' field contains
			the length of this string. The string must not
			exceed 39 characters and must contain the file
			name only; it is completed with "SYS$SHARE:.EXE".
			If the CHKLGI$M_DO_CLI_CHK flag is set, an
			attempt is made to activate the specified image.

			The default is the CLITABLES name specified
			in the target user's account; if no CLITABLES
			name is specified therein, it is "<cli>TABLES"
			(where <cli> is the name of the CLI specified
			in the CHKLGI$_CLI item code or in the target
			user's account), or "DCLTABLES", if no CLI was
			specified.

	CHKLGI$_COMMAND: when specified, simulates that the /COMMAND or
			/NOCOMMAND qualifier was specified. This is not
			allowed for accounts with the RESTRICTED or
			CAPTIVE flags set.

			The 'value' and 'length' fields are not used
			here and should be set to 0.

	CHKLGI$_DISK:   when specified, simulates that the /DISK quali-
			fier was specified. This is not allowed for
			accounts with the RESTRICTED or CAPTIVE flags.

			The 'value' and 'length' fields are not used
			here and should be set to 0.

	CHKLGI$_CONNECT: when specified, simulates that the /CONNECT
			qualifier was specified. This is not allowed for
			accounts with the RESTRICTED, DISRECONNECT or
			CAPTIVE flags set.

			The 'value' and 'length' fields are not used
			here and should be set to 0.

	This argument is meaningful for interactive logins only. It is
	optional; if omitted, no 'qualifiers' were specified.



	outitmlst
	---------

	OpenVMS usage:  item_list_3
	Type:           longword (unsigned)
	Access:         read only
	Mechanism:      by reference

	Item list which is sent to SYS$GETUAI for further evaluation.
	The itmlst argument is the address of a list of one or more
	item descriptors, each of which specifies an item code. The
	item list is terminated by an item code value of 0 or by a
	longword of 0.

	When specified, CHKLGI passes this argument directly to
	SYS$GETUAI. This allows you to perform login checks for a
	given user and obtain information about his account in a
	single call. Note that the item list is not validated by
	CHKLGI; if SYS$GETUAI detects an error, it is returned to
	CHKLGI which, for his part, passes it to its caller.

	See the description of the SYS$GETUAI system service for a
	list of available item codes.

	This argument is optional. If omitted, SYS$GETUAI is not
	invoked.
=0C

	Description
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	CHKLGI checks whether a given user may login according
	many criterias. It perform almost the same operations as
	LOGINOUT.EXE, the OpenVMS login image, including proxy
	processing, ALF (automatic login facility) processing,
	system alarm auditing and intrusion database handling.

	CHKLGI performs the following steps which are described
	in the approbiate sections:

	1) if not supplied, obtain a username;
	2) perform all adequate login checks for the given login
	   type (unless a check was explicitly disabled);
	3) if requested, update the intrusion database;
	4) if requested, update some fields in the target user's
	   account;
	5) unless disabled, send the login event to the auditing
	   system.
=0C

	1) Obtaining a username
	-----------------------

	CHKLGI provides several ways to obtain a username which
	is used for all further checks. The first, most usual way
	is specifying the name in the 'usrnam' argument; this
	name, which must exist in the UAF, is further used; it
	becomes the 'target user'.

	If the specified name does not exist, the status
	LGI$_NOSUCHUSER is returned.

	Two other ways exist to obtain a 'targer user' as well:

	o - For network logins, a proxy may map a "REMNOD::REMUSR"
	    string to a local username.

	o - For interactive logins, the VMS automatic login
	    facility (ALF) may map a "REMNOD::REMUSR" or
	    "SERVER/PORT" string to a valid username.

	CHKLGI uses these features in the following way:

	o - For network logins, if you omit the 'usrnam' argument
	    and specify the 'reminf' argument ("REMNOD::REMUSR"),
	    the proxy database is scanned to find a proxy with
	    the string given in 'reminf'. This proxy must have an
	    username entry marked as DEFAULT; this entry becomes
	    the target user.

	o - For network logins, if you specify BOTH, the 'usrnam'
	    AND the 'reminf' argument, the proxy database is
	    scanned to find a proxy with the string given in
	    'reminf'. This proxy must have the username entry
	    specified in 'usrnam', it becomes the target user.

	    If you omit the username and specify a non-existent
	    proxy, the status LGI$_NOTVALID is returned.

	    Consider these examples:

	    UAF> ADD/PROXY ALPHA1::TEST   TEST,BOL/DEFAULT

	    reminf =3D "ALPHA1::TEST",
	    usrnam =3D 0			-> Resultant name =3D "BOL"

	    reminf =3D "ALPHA1::TEST",
	    usrnam =3D "TEST"		-> Resultant name =3D "TEST"

	    reminf =3D "ALPHA1::TEST",
	    usrnam =3D "TEST_NEU"		-> Return status =3D LGI$_NOSUCHUSER

	    reminf =3D "BETA1::TEST",
	    usrnam =3D ""			-> Return status =3D LGI$_NOTVALID

	    Note that proxy processing is supported only under
	    VAX/VMS V6.1 and higher and OpenVMS Alpha V6.2 and
	    higher. On older VMS versions, you must supply the
	    'usrnam' argument, otherwise, the status LGI$_NOTVALID
	    is returned.

	o - For remote interactive logins, if you omit the 'usrnam'
	    argument and specify the 'reminf' argument, the ALF
	    database (usually SYS$SYSTEM:SYSALF.DAT) is scanned
	    with the key given in 'reminf'. If a matching entry
	    is found, the resultant username is used further.

	    Note that ALF is not supported for remote logins via
	    TCP/IP (TELNET, RLOGIN).

	o - For interactive logins, you may use the 'lgidev'
	    argument to specify a login device (a terminal).
	    This device must exist and must have a device class
	    of DC$_TERM or DC$_WORKSTATION. If it has another
	    class, the status LGI$_INVINPUT is returned.

	    If you supply this argument, CHKLGI attempts to trans-
	    late the given device into a physical device name
	    (TT_PHYDEVNAM) or access port name (TT_ACCPORNAM) and
	    uses the result as search key into the ALF database.
	    If a matching entry is found, it is used. If no
	    matching entry is found, the status LGI$_NOTVALID
	    is returned.

	    The following standard access port names exist:

	    "REMNOD::REMUSR"	for remote interactive logins via
				DECnet,

	    "VMSNAM/UIC_gggmmm"	for local interactive logins via
				LAT from a VMS host,

	    "SRVNAM/PORT_n"	for local interactive logins via
				LAT from a terminal server,

	    "TTan:" or "TXan:"	for local or dialup interactive
				logins, over serial line or via
				modem.

	    There are additional formats for access port names
	    used by some TCP/IP and X.25 software packages; see
	    the description of your package.

	    Note that ALF is not used if the system console device
	    (OPA0:) is specified in 'lgidev'. In this case, you
	    _must_ supply an username.

	You _must_ specify the 'usrnam' argument for detached,
	batch and DECwindows logins since there is no other way
	with these login types to obtain an username.

	Table T-1 shows which arguments must be specified for
	the different login types.


	Table T-1 - Arguments for login types:

	Login type	usrnam		lgidev		reminf	Notes
	-------------------------------------------------------------
	DETACHED	Req		Opt		NA
	BATCH		Req		NA		NA
	NETWORK		Opt		NA		Opt	1)
	LOCAL		Opt		Opt		NA	1)
	REMOTE		Opt		Opt		Opt	2)
	DIALUP		Opt		Opt		NA	1)
	DECWINDOWS	Req		Opt		NA

	Req...required
	Opt...optional
	NA....not allowed

	1) At least one of the both args must be specified.
	2) At least one of the three args must be specified.

	If you specify an argument which is not allowed for a
	specific login type, the status SS$_CONFQUAL is returned.
=0C

	2) Login Checks
	---------------

	CHKLGI performs all possible checks which are adequate
	for the given login type. Every check may be disabled
	by setting the approbiate bit in the 'flags' argument;
	password checks are suppressed by omitting the 'paswd1'
	and 'paswd2' arguments. All checks are shortly described
	in the following sections.

	If a check fails, CHKLGI returns the approbiate status,
	usually a login-related error (LGI$_xxxx). Further
	checks are not performed in this case. All checks are
	performed in the sequence in which they are described
	in the following sections.

	The following checks are bypassed if the 'login' occurs
	on the system console (OPA0:) with username SYSTEM (this
	is called 'system-console login'):

	o - Password expiration
	o - Account expiration
	o - Account disabled
	o - Login hour
	o - Login day
	o - VMS and VMScluster license

	In addition, all checks are bypassed for system console
	logins with selected, but non-existent alternate UAF. In
	this case, (if the alternate UAF does not exist and the
	system parameter UAFALTERNATE is set to 1), user SYSTEM
	may login on the console with any password (this is the
	'last chance' for a system manager who has forgotten the
	system password).

        By default, the 'login' will occur on the current time
	(the time of the system clock). You may, however, specify
	another time by using the 'lgitim' argument. This may
	affect the results of the following checks:
=20
	o - Password expiration
	o - Account expiration
	o - Login hour
	o - Login day

	In addition, the specified time appears in the generated
	audit/alarm messages and, in case of successful logins,
	is recorded in the target user's account, if the CHKLGI$M_
	UPDATE_UAF bit is set in the 'flags' argument ('last
	interactive/non-interactive login').

	If a detached process is created with RUN/DETACHED,
	LOGINOUT performs no checks against the user's account,
	unless /AUTHORIZE is specified as well. CHKLGI assumes
	that /AUTHORIZE was specified and performs all checks
	required for detached process logins (see section 2.7).
=0C

	2.1) Password-related checks
	- - - - - - - - - - - - - -

	Password-related checks include the validation of the
	password string if one was given in either the 'paswd1'
	and/or 'paswd2' argument, and passwords are defined in
	the target user's UAF record. Usually, the first (pri-
	mary) password is defined where the secondary password
	is not. Note that an account with a secondary password
	cannot be used for network logins, unless a proxy exists
	which points to it.

	If the specified password was incorrect, the status
	LGI$_INVPWD is returned.

	Password-related checks also include the check for
	password expiration, unless explicitly disabled by
	setting the CHKLGI$M_SKP_EXPPWD_CHK bit in the 'flags'
	argument. Password expiration occurs when the resultant
	time of the last password change and the password life
	time is in the past. It also occurs when the PWD_EXPIRED
	or PWD2_EXPIRED flags were set by the system manager.
	In any case, the status LGI$_PWDEXPIR is returned.

	Note that you can specify a login time with the 'lgitim'
	argument. If you do so, the password expiration time
	is checked against this time. In other words, you may
	specify a time in the future and see whether the pass-
	word(s) will have expired at this time.

	If no password life time was specified in the target
	user's account, no expiration check is made. This is
	also the case for system-console logins.
=0C

	2.2) Account-related checks
	- - - - - - - - - - - - - -

	Account-related checks include account expiration,
	account locking (disabling), the check for auto-login,
	and whether the account may be used for a DECwindows
	login. These checks are entirely skipped if a system-
	console login occurs; in addition, they can be explicitly
	disabled by setting the approbiate bits in the 'flags'
	argument (see section 2.7).

	If the account has an expiration time defined and
	this expiration time is in the past, the status LGI$_
	ACNTEXPIR is returned. Note that you can specify a
	login time with the 'lgitim' argument. If you do so,
	the account expiration time is checked against this
	time. In other words, you may specify a time in the
	future and see whether the account will have expired
	at this time.

	If the account is locked (disabled), the status LGI$_
	DISUSER is returned.

	If the account has the AUTOLOGIN flag set, it can be
	used only for auto-logins via the ALF mechanism. In
	this case, you must have specified the 'reminf' or
	'lgidev' argument; this causes CHKLGI to 'attempt'
	an auto-login. If no auto-login is performed and the
	account has the AUTOLOGIN flag set, the status LGI$_
	AUTOLOGIN is returned. This check is made for inter-
	active logins only.

	The last check occurs for DECwindows logins only.
	In this case, the account must not have the CAPTIVE
	and/or RESTRICTED flags set, otherwise the status
	LGI$_DECWCAPTIVE is returned.
=0C

	2.3) Login-time related checks
	- - - - - - - - - - - - - - -

	This includes the checks for valid login hours, login
	days and login source (type). These checks are entirely
	bypassed if a system-console login occurs, and for
	detached processes. In addition, these checks can be
	explicitly disabled by setting the approbiate bits in
	the 'flags' argument (see section 2.7).

	First, a decision is made to find out whether the
	current day is a primary or secondary day. This is
	normally stored in the target user's account; however,
	the system manager can set the current day explicitly
	as either primary or secondary by using the SET DAY
	command. Doing so will override any settings in the
	UAF.

	If logins are entirely disabled for the given login
	type and for both primary and secondary days, the
	status LGI$_RESTRICT is returned.

	If logins for the given login type are disabled on
	the current day, the status LGI$_BADDAY is returned.

	Finally, the hour is computed from the login time.
	If logins are disabled for this hour, the status
	LGI$_BADHOUR is returned.

	You may specify a login day in the 'lgiday' argument.
	If you do so, this day is used for the day-related
	check; this allows you the check whether logins are
	enabled for the target user on the specific day. If
	you omit the 'lgiday' argument, but specify a login
	time ('lgitim' argument), the day is computed from
	this login time. If you omit both arguments, the login
	day is computed from the system time which is also
	used for the login hour check.

	Note that the granularity for login times is one hour.
	For example, you may specify a login time of 11:30 or
	11:40; in both cases, the check is made for the hour
	from 11:00 to 11:59.
=0C

	2.4) Login-quota related checks
	- - - - - - - - - - - - - - - -

	Login-quota related checks include the checks for
	maximum process per username, maximum processes per
	account name, and, for interactive logins only, the
	maximum number of interactive users on the system
	(established with SET LOGINS/INTERACTIVE). All these
	checks may be disabled by setting the approbiate
	bits in the 'flags' argument (see section 2.7).

	If set to a non-zero value, the UAF field MAXJOBS
	defines the maximum number of processes with the
	given username (interactive, batch, detached and
	network) which may be active simultaneously. If
	this value is exceeded, the status LGI$_USEREXC
	is returned. Note that the first four network jobs
	are not counted.

	If set to a non-zero value, the UAF field MAXACCTJOBS
	defines the maximum number of processes with the
	target user's account name, which may be active
	simultaneously. If this value is exceeded, the status
	LGI$_ACNTEXC is returned. Network jobs are ignored
	for this check.

	Note that these checks are skipped if the calling
	process has the PCB$M_NOACNT bit set in PCB$L_STS.
	In addition, only 'main' processes are counted,
	subprocesses are not counted in any way.

	Finally, the current number of interactive users must
	not be greather than the limit defined by the system
	manager. If this number was set to 0, interactive logins
	were completly disabled and the status LGI$_LOGDISABL
	is returned; otherwise, the interactive login quota was
	exceeded and this will return the status LGI$_EXQUOTA.
	Note that this check is bypassed for accounts with the
	OPER privilege set in their default privilege mask.
=0C

	2.5) Checks for command line qualifiers
	- - - - - - - - - - - - - - - - - - - -

	When entering your name in response to the "Username"
	prompt, you may specify some qualifiers as well (type
	"HELP LOGIN" for more). However, not all qualifiers
	are allowed for all accounts. The system manager may
	restrict the set of available qualifiers by setting
	bits in the 'Flags' field of the target user's account.

	The checks in this section ensure that only allowed
	qualifiers were specified.

	You tell CHKLGI that qualifiers were specified by
	using the 'initmlst' argument. Every item in the list
	simulates a specific qualifier (see the 'Arguments'
	section for a description about available items). If
	you omit the 'initmlst' argument, this simulates that
	no qualifiers were specified and the following checks
	are skipped.

	If you supply any item and either the CAPTIVE or
	RESTRICTED bits are set in the 'Flags' field of the
	target user's account, the status LGI$_CAPTIVE is
	returned.

	If you supply the CHKLGI$_CLI or CHKLGI$_TABLES items
	and the DEFCLI bit is set in the 'Flags' field of the
	target user's account, the status LGI$_DEFCLI is returned.

	Finally, if you supply the CHKLGI$_CONNECT item and the
	target user's account has the DISRECONNECT bit set in its
	'flags' field, the status LGI$_DISRECONNECT is returned.

	Note that this checks are meaningful for interactive
	logins only.
=0C

	2.6) License-related checks
	- - - - - - - - - - - - - -

	License-related checks ensure that a valid VMS license
	is loaded, and, if your system is part of a VMScluster,
	a valid VMScluster license is loaded as well. These
	checks occur for interactive logins only, they may be
	disabled by setting the approbiate bit in the 'flags'
	argument (see section 2.7).

	Table T-2 summarizes the required licenses for Alpha
	and VAX.


	Table T-2 - VMS and VMScluster license names:

			VAX			Alpha
	----------------------------------------------------------
	VMS:		VAX-VMS			OPENVMS-ALPHA
			BASE-VMS-250136		OPENVMS-ALPHA-USER

	VMScluster:	VAXCLUSTER		VMSCLUSTER
			VMSCLUSTER-CLIENT	VMSCLUSTER-CLIENT

	In addition, users with the CAPTIVE or RESTRICTED bit
	set in their account 'Flags' field may login if a
	"VMS-DAAL" license is loaded (VAX and Alpha).

	If no valid VMS license is loaded, the status LICENSE$_
	NOLICENSE is returned.

	If a valid license is loaded but its capacity is ex-
	hausted, the status LGI$_EXLICENSE is returned.

	If your system is a VMScluster member but there is no
	VMScluster license available, the status LGI$_NOVAXCLUSTER
	is returned.

	In any other case, if the run-time license checking
	system encounters an error (i.e, the license has ter-
	minated), this error is returned.

	All of the above are error conditions and cause the
	login to abort. The following _informational_ status
	codes may be returned as well:

	LGI$_LOGOPRCON (logins allowed from OPA0): This status
	  is returned, if no VMS or VMScluster license is
	  loaded, but the login occurs from the console. In
	  this case, the login is allowed and this different
	  status is returned.

	LGI$_LICNOTREQ (license check not required by this
	  process): In case of DECwindows logins, this status
	  is returned if no valid VMS or VMScluster license is
	  loaded. Since a DECwindows session is considered as
	  a single login (regardless how many DECterm windows
	  are openend), a DECwindows login without a valid
	  license causes this status to be returned.
=0C

	2.7) Summary
	- - - - - -

	Table T-3 summarizes all login checks, the names of the
	bits in the 'flags' argument to suppress them, and whether
	or not a check is performed for a specific login type. All
	checks are performed in the order listed in the table.

	The names of the suppression bits are abbreviated, the
	fullname is CHKLGI$M_SKP_<name>_CHK.


	Table T-3: Login checks:

	Check		   Suppr Bit	DET  BAT  NET  LOC  DIA  REM  DWI Notes
	-----------------------------------------------------------------------
	Bad Prim. Password 1)		 -    -    y    y    y    y    y
	Bad Scnd. Password 1)		 -    -	   y    y    y    y    y
	Password expired   EXPPWD	 y    y    y    y    y    y    y   2)
	Account disabled   DISACC	 y    y    y    y    y    y    y   2)
	Account expired    EXPACC	 y    y	   y    y    y    y    y   2)
	Auto logins only   ALOGIN	 -    -    y    y    y    y    y
	DECwinds. captive  DWICAP	 -    -    -    -    -    -    y
	Bad login source   SRC		 -    y    y    y    y    y    y   2)
	Bad login day      DAY           -    y    y    y    y    y    y   2)
	Bad login hour     HOUR          -    y    y    y    y    y    y   2)
	Login quota exc.   MAXINT        -    -    -    y    y    y    y   3)
	Logins disabled    LGIDIS	 -    -    -    y    y    y    y   3)
	Max. proc/account  MAXACC	 y    y    y    y    y    y    y   4)
	Max. proc/user	   MAXUSR	 y    y    y    y    y    y    y   4)
	Command qualifiers 5)		 -    -    -    y    y    y    y
	No licenses loaded LIC		 -    -    -    y    y    y    y   2)
	Breakin evasion	   6)		 y    -    y    y    y    y    y

	1) To suppress this check, omit the 'paswd<n>' arguments.

	2) This check is skipped if a system-console login occurs
	   (usrnam=3D "SYSTEM", lgidev=3D "OPA0:").

	3) This check is suppressed if the target user has the
	   OPER privilege set in its default privilege mask.

	4) This check is suppressed for processes with the
	   PCB$M_NOACNT bit set in PCB$L_STS.

	5) To suppress these checks, omit the 'initmlst' argument.

	6) A check for breakin-evasion occurs only if you
	   have set the CHKLGI$M_INTRUSION bit in the 'flags'
	   argument. See chapter 3.
=0C

	3) Intrusion processing
	-----------------------

	If you set the CHKLGI$M_INTRUSION bit in the 'flags'
	argument, CHKLGI calls the SYS$SCAN_INTRUSION system
	service to perform intrusion processing. This service,
	which communicates with the SECURITY_SERVER process to
	maintain the intrusion database, is available on VAX/VMS
	V6.1 or higher, and OpenVMS Alpha V6.2 or higher only;
	this feature is not available on older VMS versions.

	Intrusion processing is not done for batch logins and
	occurs for the following kinds of login failures only:

	LGI$_NOTVALID - a valid username could not be obtained;
	LGI$_NOSUCHUSER - an unknown username was specified;
	LGI$_INVPWD - an invalid password was specified;
	LGI$_DISUSER - target user's account is disabled.

	Intrusion processing works as follow:

	Whenever one of the above login failures occurs, a data
	structure called an 'intrusion record' is created. It
	contains the origin of the login (username, terminal
	name, remote node/user) which caused the failure, the
	intrusion type (initially set to "SUSPECT"), a counter
	which stores the number of failures from this origin
	(initially 1), and an expiration time (the sum of the
	current time and the value of LGI_BRK_TMO).

	You may show intrusion records with SHOW INTRUSION;
	existing records may be deleted by DELETE/INTRUSION.
	Both commands require SECURITY privilege.

	Whenever a login failure occurs for a record with an
	already-existing origin, a check is made to see whether
	its intrusion type is still set to "SUSPECT". If it is,
	the intrusion counter is incremended and the value of
	the system parameter LGI_BRK_TMO is added to the
	record's expiration time. If the counter exceeds the
	value of the system parameter LGI_BRK_LIM, the intrusion
	type of the record switches yo "INTRUDER".

	Any login attempt for an intrusion record marked as
	"INTRUDER" is rejected, even if the given username and
	password were valid. This situation is called 'breakin-
	evasion', it is indicated by the return status LGI$_
	EVADE. If the system parameter LGI_BRK_DISUSER is set,
	the target user's account is locked against any further
	logins as well (the DISUSER flag is set). In order to
	re-make this account available for logins, the system
	manager must clear the DISUSER flag manually.

	Note that the intrusion counter is incremented and the
	expiration time is extended during breakin-evasion as
	well. The more login failures occur, the longer the
	breakin-evasion will continue. When the expiration time
	is reached, the record type is switched back to "SUSPECT",
	the counter is set to the value of LGI_BRK_LIM and the
	expiration time is set to the current time plus the
	value of LGI_BRK_TMO. From this point, logins are re-
	allowed from the origin (assuming that the account was
	not disabled), but monitoring still continues. When the
	second expiration time is reached, the record is deleted
	from the intrusion database. From this time, the origin
	is not longer monitored; if a login failure occurs, a
	new intrusion record is created and intrusion processing,
	as described above, starts again.

	For a valid login, an existing intrusion record is not
	deleted; it just remains unchanged. The deletion occurs
	when the timer of the record expires or when the command
	DELETE/INTRUSION is entered.

	The following kinds of intrusion origins exist:

	#  Origin	Contents		Examples
	--------------------------------------------------------------------
	1) USERNAME	Username		BOL
	2) TERMINAL	Terminal or AccPort	_TTA2:, DS2033/PORT_1
	3) TERM_USER	Term:User or Accp:User	_TTA2:BOL, DS0233/PORT_1:BOL
	4) NETWORK	REMNOD::REMUSR		MIC013::BOL

	1) This kind of origin is used when no other information
	   than the username is available. If you call CHKLGI with
	   the 'usrnam' argument only (no 'lgidev' and 'reminf'
	   args) and the login fails, this type of intrusion record
	   is created. VMS uses it for detached processes and for
	   interactive logins when the system parameter LGI_BRK_
	   TERM is set to 0 (in this case, no terminal-specific
	   information should be used to build the origin string;
	   this is useful for logins over virtual terminals, where
	   the terminal name differs from login to login).

	2) This origin includes a terminal name, either the
	   physical name (TTAn:, TXAn:) or LAT access port
	   information (SERVER/PORT). For logins over TCP/IP or
	   X.29, it may include other information as well; the
	   format depends on the used TCP/IP or X.29 package.
	   Intrusion records with this format are created when
	   you specify the 'lgidev' argument without 'usrnam' or
	   'usrnam' with a non-existent user. VMS uses this origin
	   for local and dialup login failures and for remote
	   login failures if they occur over X.29 or TCP/IP.

	3) This is the combination of 1) and 2); it is used for
	   local and dialup login failures with a valid username
	   (either obtained via proxy/ALF or supplied). CHKLGI
	   creates an intrusion record with this format if you
	   specify the 'usrnam' argument with a valid username
	   and the 'lgidev' argument, but the login failed for
	   other reason (i.e, invalid password). This origin is
	   converted to USERNAME when the parameter LGI_BRK_TERM
	   is set to 0.

	4) This origin is used for network login failures and
	   for interactive remote login failures over DECnet.
	   It always includes a "REMNOD::REMUSR" string.

	Table T-4 shows how the different intrusion origins are
	created by CHKLGI, depending on the given arguments.


	Table T-4 - Intrusion origins created by CHKLGI:

	usrnam		lgidev		reminf		Origin
	---------------------------------------------------------
	<novalid> 1)	-		-		USERNAME
	<novalid> 1)	TTxn:,LTAn:	-		TERMINAL
	<novalid> 1)	RTAn:		-		NETWORK
	<novalid> 1)	-		REMNOD::REMUSR	NETWORK
	<valid> 2)	-		-		USERNAME
	<valid> 2) 3)	TTxn:,LTAn:	-		TERM_USER
	<valid> 2)	RTAn:		-		NETWORK
	<valid> 2)	-		REMNOD::REMUSR	NETWORK

	1) <novalid> means either an incorrect username was
	   specified or the 'usrnam' argument was omitted.

	2) <valid> means that a valid username was specified or
	   could be obtained with ALF or proxy processing. The
	   login failed for other reason (i.e., invalid password).

	3) If the system parameter LGI_BRK_TERM is set to 0,
	   this origin is converted to USERNAME.
=0C

	4) UAF record update
	--------------------

	You can force CHKLGI to update the target user's account
	by setting the CHKLGI$M_UPDATE_UAF bit in the 'flags'
	argument. If a valid user was specified or obtainend,
	the following fields in its account are updated:

	o) Successful login: depending on the login source,
	   either the 'Last interactive login' or the 'Last
	   non-interactive login' field is set to the current
	   time or the time passed in the 'lgitim' argument.
	   In addition, the 'Login fails' count is reset to 0.

	o) Login failure: the 'Login fails' count is incremented.

	Note that in case of breakin-evasions, the 'Flags' field
	may be updated as well (by setting the DISUSER bit, see
	previous chapter).

	To perform the update, the SYS$SETUAI system service
	is used. This causes the generation of a "System UAF
	record modification" event message if security alarms/
	audits are enabled for "Authorization". Note that this
	is different from LOGINOUT which uses RMS to read and
	update UAF records and therefore does not generate
	this kind of event messages.

	In VMS versions pre V6.0, the above account fields were
	read-only. You could read their contents with SYS$GETUAI
	but specifying them in the item list to SYS$SETUAI
	caused a SS$_BADPARAM status to be returned. This status
	is ignored by CHKLGI here and is not returned to its
	caller; however, for this reason, the update UAF feature
	is not possible on pre-V6 VMS versions.
=0C

	5) Auditing
	-----------

	Unless you set the CHKLGI$M_NO_AUDIT bit (this requires
	SECURITY privilege) in the 'flags' argument, logins and
	login failures 'performed' by CHKLGI are audited as
	event messages by sending them to the VMS alarm/audit
	system. This causes the approbiate messages to be
	displayed on all operator terminals with SECURITY class
	enabled and to be inserted into the system audit journal
	file.

	CHKLGI uses the SYS$AUDIT_EVENT system service to generate
	event messages. This service is supported on VAX/VMS V6.0
	and later and OpenVMS AXP V6.1 and later. Therefore, on
	older VMS versions, auditing is not possible.

	CHKLGI always performs auditing, regardless of the
	settings of the 'Login', 'Logfailure' and 'Breakin'
	event status. This prevents users from 'playing' with
	CHKLGI unnoticed (i.e., to guess passwords).

	The event messages generated by CHKLGI should be inter-
	preted in a slightly different way than those of LOGINOUT.
	Consider this example:

	%%%%%%%%%%%  OPCOM  15-JUL-1997 15:24:02.88  %%%%%%%%%%%
	Message from user AUDIT$SERVER on AXP014
	Security alarm (SECURITY) and security audit (SECURITY) on AXP014,
	system id: 2151
	Auditable event:          Local interactive login failure
	Event time:               15-JUN-1997 20:24:02.76
	PID:                      00000082
	Process name:             FERRY_LTA122
	Username:                 BOL
	Process owner:            [BOL]
	Terminal name:            LTA122:, _LTA122:, SRV002/PORT_3
	Image name:               AXP014$DKA300:[BOL.CHKLGI]LOGIN.EXE;1
	Status:                   %LOGIN-F-INVPWD, invalid password


	Note the following:

	o - The following events may be generated by CHKLGI:

	    <lgisrc> login - a successful 'login' (all checks
	    were passed successfully);

	    <lgisrc> login failure - an error was encountered
	    while obtaining a username or performing a login
	    check;

	    <lgisrc> breakin - a breakin-evasion is in progress.

	o - If a login time was supplied with the 'lgitim'
	    argument, it is listed in the 'Event time' line.
	    The time in the OPCOM header contains the actual
	    time at which the event occured.

	o - The 'PID' and 'Process name' lines contain the PID
	    and the name of the process which has called CHKLGI.
	    In addition, the 'Image name' contains the full file
	    specification of the image wherein CHKLGI was called.
	    This information cannot be changed or suppressed and
	    allows the system manager to identify the program,
	    and the process who has used CHKLGI.

	o - The remaining lines are generated based on the given
	    information:

	    The 'Username' and 'Process owner' lines contain
	    the name and the UIC of the supplied or obtained
	    user. In alarm messages, if no valid username was
	    given, the following pseudo strings are substituted:

	    <login>	for all kinds of interactive logins,
	    <batch>	for batch logins,
	    <net>	for network logins, and
	    <det>	for detached logins.

	    On pre-V6 systems, these strings are logged in the
	    audit journal as well; starting with VMS V6, the
	    specified username, even if it does not exist, is
	    written into the journal.

	    The above pseudo strings are also used in both,
	    alarm and audit messages, if no valid username
	    could be obtained by proxy or ALF processing (the
	    return status is LGI$_NOTVALID).

	    In the case of detached logins or login failures,
	    the 'Username' line contains a 'Parent username'
	    string as well: this is the username of the process
	    which has called CHKLGI.

	    The 'Terminal name' contains the string given in
	    'lgidev', the translated physical device name and
	    the access port name, if available. This line appears
	    for interactive logins only and for detached logins,
	    if the 'lgidev' argument was specified.

	    If a 'reminf' argument was supplied or an RTAn:
	    (DECnet remote login) terminal was given in 'lgidev',
	    three lines are included in addition:

		Remote nodename:          MIC013
		Remote node id:           2141 (2.93)
		Remote username:          TEST

	    The strings listed in 'Remote nodename' and 'Remote
	    username' are those given in 'reminf' or are obtained
	    from the RTAn: terminal's access port name string.
	    The node id is obtained from the DECnet node database;
	    if the specified nodename is unknown or DECnet is not
	    running, "0 (0.0)" is displayed instead.

	    If a password was specified, it is included in the
	    event message while breakin-evasion is active. Note
	    that the inclusion occurs for audit records only;
	    passwords are never displayed in alarm messages. In
	    addition, only invalid passwords are recorded; if
	    the given password was valid, the string "<valid>"
	    is substituted instead.

	o - As mentioned earlier, the 'Image name' line contains
	    the full name of the image wherein CHKLGI was called.
	    If you're unsure whether an audit message was gene-
	    rated by CHKLGI, look at this line. If you cannot
	    find it in the event message, the line was generated
	    by LOGINOUT which does not include its image name in
	    its event messages.

	o - Finally, the 'Status' line contains the status of the
	    'login operation'. This status will be returned by
	    CHKLGI to its caller. The line is displayed only for
	    login failures or while breakin-evasion is active.
=0C

	6) Restrictions
	---------------

	CHKLGI performs allmost the same operations as LOGINOUT
	when validating a login request and performing the
	login. However, the following functions and options
	are not supported by CHKLGI:

	o) Login extensions (LOGINOUT callbacks to perform
	   external user validation) - this feature will be
	   implemented in a future release);

	o) For interactive logins, system password checks;

	o) Checks for subprocess logins - checks based on
	   subprocesses are not made by LOGINOUT and there-
	   fore not by CHKLGI;

	o) For network logins, checks for privileged and non-
	   privileged DECnet users or for object-based user
	   definitions. These checks are made by the DECnet
	   software (NET[$]ACP process) which passes the
	   resultant name string to LOGINOUT.

	CHKLGI may be called from user and supervisor mode
	only. Therefore, it may not be part of privileged
	code and may not be called from code in a privileged
	shareable image.

	To run CHKLGI, you need at least VAX/VMS V5.4 or
	OpenVMS AXP V1.5. In addition, table T-5 shows the
	VMS version requirements for different functions
	provided by CHKLGI.


	Table T-5 - VMS version requirements:

	Function			Flag name	VAX	Alpha
	-------------------------------------------------------------------
	Proxy processing		1)		V6.0	V6.1
	Auditing of login attempts	2)		V6.1	V6.2
	Intrusion processing		INTRUSION	V6.1	V6.2
	Update of UAF record		UPDATE_UAF	V6.0	V6.1

	1) Proxy processing occurs when the 'reminf' argument is
	   specified and the login source is CHKLGI$_NETWORK.

	2) Auditing can be disabled by setting the CHKLGI$M_NO_AUDIT
	   bit in the 'flags' argument.



	Required privileges
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

	To use this routine, you need SYSPRV, CMKRNL and AUDIT
	privileges. If you specify the CHKLGI$M_NO_AUDIT flag
	(suppress auditing) or the CHKLGI$M_INTRUSION flag
	(use and update the intrusion database), you need SECURITY
	privilege as well.
=0C

	Condition values returned
	=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D


	System values:
	--------------

	SS$_NORMAL:	a valid username was found or was obtained
			by proxy or ALF processing and all checks
			were performed successfully.

	SS$_NOAUDIT:	AUDIT privilege is required.

	SS$_NOCMKRNL:	CMKRNL privilege is required.

	SS$_SECURITY:	SECURITY privilege is required.

	SS$_NOSYSPRV:	SYSPRV privilege is required.

        SS$_BADPARAM:	a string argument is too long or has
			incorrect format or the given login source
			is invalid or an invalid item code was
			specified.

        SS$_CONFQUAL:	an invalid argument combination (missing
			or conflicting arguments) was given.


	Login-specific values:
	----------------------

	LGI$_ACNTEXC:	too many processes for this account.

	LGI$_ACNTEXPIR:	user's account has expired.

	LGI$_AUTOLOGIN:	user's account is for auto-login only.
=20
	LGI$_BADDAY:	no login allowed at this day.

	LGI$_BADHOUR:	no login allowed at this time.

	LGI$_CAPTIVE:	no qualifiers allowed in captive accounts.

	LGI$_CLIFAIL:	error activating command interpreter.

	LGI$_CLITBLFAIL: error activating command interpreter tables.

	LGI$_DECWCAPTIVE: no DECwindows login on captive account.

	LGI$_DISRECONNEC: no reconnections allowed.

	LGI$_DISUSER:	user's account is disabled.

	LGI$_DEFCLI:	CLI-related qualifiers are not allowed.

	LGI$_EVADE:	Breakin-evasion is in effect.

	LGI$_EXLICENSE:	licensed number of system users exceeded.

	LGI$_EXQUOTA:	maximum number of interactive users exceeded.

	LGI$_FILEACC:	error accessing UAF or alternate UAF.

	LGI$_INVINPUT:	the device given in the 'lgidev' argument is
			not a terminal or workstation device.

	LGI$_INVPWD:	given password does not match with password
			in UAF.

	LGI$_LICNOTREQ:	no license check required for this process
			(informational status).

	LGI$_LOGDISABL:	interactive logins are currently disabled.

	LGI$_LOGOPRCON:	no VMS or VMSCLUSTER license found, but
			logins are allowed from OPA0: (informational
			status).

	LGI$_PWDEXPIR:	password in UAF is marked as (pre-) expired.

	LGI$_NOSUCHUSER: the given username does not exist.

	LGI$_NOTVALID:	either there was no correspondig proxy
			(remote/network) or no corresponding record
			in the ALF database (local/dialup).

	LGI$_NOTMODEM:  modem not wired correctly (terminal was set
			to /MODEM but is not a remote device).

	LGI$_NOVAXCLUSTER: no (valid) VMSCLUSTER(VAXCLUSTER) license
			found.

	LGI$_RESTRICT	no login allowed from this source.

	LGI$_USEREXC:	too many processes for this user.
=20

        Any other error codes returned by the following system
	services:

	SYS$AUDIT_EVENTW	SYS$CMKRNL		SYS$GETDVIW
	SYS$GETTIM		SYS$GETUAI		SYS$GRANT_LICENSE
	SYS$HASH_PASSWORD	SYS$IMGACT		SYS$LOOKUP_LICENSE
	SYS$RELEASE_LICENSE	SYS$SCAN_INTRUSION	SYS$SETUAI
	SYS$VERIFY_PROXY


        Any other error codes returned by the following RMS
	services:

        SYS$CONNECT	SYS$CLOSE	SYS$GET 	SYS$OPEN


        Any other error codes returned by following RTL routines:
=20
	LIB$ADD_TIMES		LIB$CVT_FROM_INTERNAL_TIME
	LIB$DAY_OF_WEEK		LIB$GETJPI		LIB$GETSYI

=0C---------------------->>> #3: BUILD_OLB.COM <<<----------------------

$ !
$ ! BUILD_OLB.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! Build CHKLGI_'platform'.OLB object library and LOGIN.OBJ, the
$ ! object for the login test tool.
$ !
$ ! (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at)
$ !
$ put :=3D writ sys$output
$ on erro then goto E_EXIT
$ cc2 =3D ""
$ v =3D f$gets ("VERSION")
$ maj =3D f$extr (1,1,v)
$ min =3D f$extr (3,1,v)
$ x =3D "V6_NOK"
$ if f$gets ("HW_MODEL") .gt. 1024
$ !
$ ! ALPHA
$ ! =3D=3D=3D=3D=3D
$ !
$ then
$ DECC =3D f$sear ("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. ""
$ if .not. DECC
$ then
$ put ""
$ put "DEC C compiler not installed on this system. Abort. "
$ put ""
$ exit
$ endi
$ if maj .ge. 7 .or. (maj .eq. 6 .and. min .ge. 2) then x =3D "V6_OK"
$ olb1 =3D "CHKLGI_AXP.OLB"
$ login1 =3D "LOGIN_AXP.OBJ"
$ cc1 =3D "cc/nodebu/opti/stan=3Dvaxc/defi=3D''x'"
$ mc_cmd =3D "macr/nodebu/opti"
$ !
$ ! VAX
$ ! =3D=3D=3D
$ !
$ else
$ DECC =3D f$sear ("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. ""
$ VAXC =3D f$sear ("SYS$SYSTEM:VAXC.EXE") .nes ""
$ if .not. DECC .and. .not. VAXC
$ then
$ put ""
$ put "Neither DEC C nor VAX C compiler installed on this system. Abort."
$ put ""
$ endi
$ if maj .ge. 7 .or. (maj .eq. 6 .and. min .ge. 1) then x =3D "V6_OK"
$ VAXC =3D VAXC .and. (p1 .eqs. "" .or. p1 .eqs. "VAXC")
$ DECC =3D DECC .and. (p1 .eqs. "" .or. p1 .eqs. "DECC")
$ if VAXC
$ then
$ olb1 =3D "CHKLGI_VAX_VAXC.OLB"
$ login1 =3D "LOGIN_VAX_VAXC.OBJ"
$ if .not. DECC
$ then cc1 =3D "cc/nodebu/opti/defi=3D''x'"
$ else
$ cc1 =3D "cc/vaxc/nodebu/opti/defi=3D''x'"
$ cc2 =3D "cc/decc/nodebu/opti/stan=3Dvaxc/defi=3D''x'"
$ olb2 =3D "CHKLGI_VAX_DECC.OLB"
$ login2 =3D "LOGIN_VAX_DECC.OBJ"
$ endi
$ else
$ olb1 =3D "CHKLGI_VAX_DECC.OLB"
$ login1 =3D "LOGIN_VAX_DECC.OBJ"
$ cc1 =3D "cc/decc/nodebu/opti/stan=3Dvaxc/defi=3D''x'"
$ endi
$ mc_cmd =3D "macr/nodebu"
$ endi
$ !
$ writ sys$output f$time()
$ olb =3D olb1
$ cc_cmd =3D cc1
$ login =3D login1
$ gosu BUILD_OLB
$ if cc2 .nes. ""
$ then
$ olb =3D olb2
$ cc_cmd =3D cc2
$ login =3D login2
$ gosu BUILD_OLB
$ endi
$ writ sys$output f$time()
$ exit
$ !
$ ! =0C=20
$ !
$ BUILD_OLB:
$ if f$sear (olb) .eqs. ""
$ then
$ x =3D f$veri(1)
$ libr/crea 'olb'
$ !'f$veri(0)'
$ endi
$ mod_list =3D "audevt,chkitm,chklgi,chklic,chkpwd,chkquo,chktim,getusr,i=
ntrus,upduaf"
$ n =3D 0
$ L_1:
$ mod =3D f$elem (n,",",mod_list)
$ if mod .eqs. "," then goto E_1
$ x =3D f$veri(1)
$ 'cc_cmd' 'mod'
$ libr/repl 'olb' 'mod'
$ !'f$veri(0)'
$ dele/nolog 'mod'.obj.
$ n =3D n + 1
$ goto L_1
$ E_1:
$ x =3D f$veri(1)
$ 'mc_cmd' _getquo+sys$share:lib/libr
$ libr/repl 'olb' _getquo
$ dele/nolog _getquo.obj.
$ 'mc_cmd' _nam_2_add+sys$share:lib/libr
$ libr/repl 'olb' _nam_2_add
$ dele/nolog _nam_2_add.obj.
$ 'cc_cmd'/obje=3D'login' login
$ !'f$veri(0)'
$ retu
$ !
$ E_EXIT:
$ !'f$veri(0)'
$ exit

=0C---------------------->>> #4: BUILD_LOGIN.COM <<<---------------------=
-

$ !
$ ! BUILD_LOGIN.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! Builds LOGIN.EXE, the tool to check the CHKLGI() routine.
$ !
$ ! (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at)
$ !
$ put :=3D writ sys$output
$ on erro then goto E_EXIT
$ if f$gets ("HW_MODEL") .gt. 1024
$ !
$ then
$ OK1 =3D f$sear ("CHKLGI_AXP.OLB") .nes. ""
$ OK2 =3D f$sear ("LOGIN_AXP.OBJ") .nes. ""
$ if .not. OK1 .or. .not. OK2
$ then
$ put ""
$ put "Object library and/or main object file not found. Abort. "
$ put ""
$ exit
$ endi
$ put ""
$ x =3D f$veri(1)
$ link/notrac/syse/exec=3Dlogin login_axp, -
sys$disk:[]chklgi_axp/libr
$ !'f$veri(0)'
$ login :=3D=3D $sys$disk:[]login
$ put ""
$ put "Build complete. Type ""LOGIN ?"" for help."
$ put ""
$ exit
$ !
$ else
$ c =3D 0
$ OK1 =3D f$sear ("CHKLGI_VAX_DECC.OLB") .nes. ""
$ OK2 =3D f$sear ("LOGIN_VAX_DECC.OBJ") .nes. ""
$ if OK1 .and. OK2 .and. (p1 .eqs. "" .or. p1 .eqs. "DECC")
$ then
$ put ""
$ x =3D f$veri(1)
$ link/notrac/exec=3Dlogin sys$input/opti
login_vax_decc
sys$disk:[]chklgi_vax_decc/libr
sys$system:sys.stb/sele
$ !'f$veri(0)'
$ c =3D 1
$ goto END
$ endi
$ OK1 =3D f$sear ("CHKLGI_VAX_VAXC.OLB") .nes. ""
$ OK2 =3D f$sear ("LOGIN_VAX_VAXC.OBJ") .nes. ""
$ if OK1 .and. OK2 .and. (p1 .eqs. "" .or. p1 .eqs. "VAXC")
$ then
$ put ""
$ x =3D f$veri(1)
$ link/notrac/exec=3Dlogin sys$input/opti
login_vax_vaxc
sys$disk:[]chklgi_vax_vaxc/libr
sys$share:vaxcrtl/shar
sys$system:sys.stb/sele
$ !'f$veri(0)'
$ c =3D 1
$ endi
$ END:
$ if .not. c
$ then
$ put ""
$ put "Object libraries/and or main object files not found. Abort. "
$ put ""
$ else
$ login :=3D=3D $sys$disk:[]login
$ put ""
$ put "Build complete. Type ""LOGIN ?"" for help."
$ put ""
$ endi
$ exit

=0C---------------------->>> #5: BUILD_DEF_AND_LIB.COM <<<---------------=
-------

$ !
$ ! BUILD_DEF_AND_LIB.COM
$ ! =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
$ !
$ ! Procedure to build language-sepific includes files and libraries.
$ !
$ ! (P) 1992 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at)
$ !
$ put :=3D writ sys$output
$ langs =3D "BASIC,BLISS,COBOL,DIBOL,FORTRAN,MACRO,PASCAL,PLI"
$ !
$ L_1:
$ if p1 .eqs. "" then inqu p1 "Language"
$ if p1 .eqs. "" then exit
$ if f$loca(p1,langs) .eq. f$leng(langs) .or. f$leng(p1) .lt. 2
$ then
$ put ""
$ put "Invalid language specified - supported languages are:"
$ put "''langs'"
$ put ""
$ p1 =3D ""
$ goto L_1
$ endi
$ gosu DO_'f$extr(0,2,p1)'
$ p1 =3D ""
$ goto L_1
$ !
$ ! =0C$ !
$ DO_BA:
$ deffil =3D "$CHKLGIDEF.BAS"
$ cmnt1  =3D "! "
$ cmnt2  =3D ""
$ defcmd =3D "      DECLARE LONG CONSTANT"
$ asscmd =3D "=3D"
$ endcmd =3D ""
$ prfcmd1 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 60
$ gosu CREATE_DEFFIL
$ dclcmd1  =3D "    %IF %DECLARED(%BASIC$QUADWORD_DECLARED) =3D 0 %THEN"
$ dclcmd2  =3D "        RECORD BASIC$QUADWORD"
$ dclcmd3  =3D "                LONG FILL(2)"
$ dclcmd4  =3D "        END RECORD"
$ dclcmd5  =3D "    %LET %BASIC$QUADWORD_DECLARED =3D 1"
$ dclcmd6  =3D "    %END %IF"
$ dclcmd7  =3D ""
$ dclcmd8  =3D "    EXTERNAL LONG FUNCTION CHKLGI (&"
$ dclcmd9  =3D "             STRING BY DESC, &          ! usrnam"
$ dclcmd10 =3D "             STRING BY DESC, &          ! lgidev"
$ dclcmd11 =3D "             STRING BY DESC, &          ! reminf"
$ dclcmd12 =3D "             STRING BY DESC, &          ! paswd1"
$ dclcmd13 =3D "             STRING BY DESC, &          ! paswd2"
$ dclcmd14 =3D "             LONG BY REF, &             ! lgisrc"
$ dclcmd15 =3D "             BASIC$QUADWORD BY REF, &   ! lgitim"
$ dclcmd16 =3D "             LONG BY REF, &             ! lgiday"
$ dclcmd17 =3D "             LONG BY REF, &             ! flags"
$ dclcmd18 =3D "             ANY BY REF, &              ! initmlst"
$ dclcmd19 =3D "             ANY BY REF)                ! outitmlst"
$ dclcmd20 =3D "###"
$ rtnfil =3D "CHKLGI$RTN.BAS"
$ gosu CREATE_RTNFIL
$ libfil =3D "BASIC$CHKLGI.TLB"
$ gosu CREATE_LIB
$ retu
$ !
$ ! =0C$ !=20
$ DO_BL:
$ deffil =3D "$CHKLGIDEF.REQ"
$ cmnt1  =3D "! "
$ cmnt2  =3D ""
$ defcmd =3D "literal"
$ asscmd =3D "=3D"
$ endcmd =3D ";"
$ prfcmd1 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 40
$ gosu CREATE_DEFFIL
$ rtnfil =3D "CHKLGI$RTN.REQ"
$ dclcmd1 =3D "EXTERNAL ROUTINE CHKLGI : BLISS ADDRESSING_MODE (GENERAL);=
"
$ dclcmd2 =3D "###"
$ gosu CREATE_RTNFIL
$ retu
$ !
$ ! =0C$ !=20
$ DO_CO:
$ deffil =3D "$CHKLGIDEF.COB"
$ cmnt1  =3D "* "
$ cmnt2  =3D ""
$ defcmd =3D "01"
$ asscmd =3D "PIC S9(9) COMP VALUE"
$ endcmd =3D "."
$ prfcmd1 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 50
$ gosu CREATE_DEFFIL
$ retu
$ !
$ ! =0C$ !=20
$ DO_DI:
$ deffil =3D "$CHKLGIDEF.DBL"
$ cmnt1  =3D "; "
$ cmnt2  =3D ""
$ defcmd =3D "   "
$ asscmd =3D ",  I4,  "
$ endcmd =3D ""
$ prfcmd1 =3D "LITERAL"
$ prfcmd2 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 40
$ gosu CREATE_DEFFIL
$ retu
$ !
$ ! =0C$ !=20
$ DO_FO:
$ deffil =3D "$CHKLGIDEF.FOR"
$ cmnt1  =3D "! "
$ cmnt2  =3D ""
$ defcmd =3D "        PARAMETER"
$ asscmd =3D "=3D"
$ endcmd =3D ""
$ prfcmd1 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 50
$ gosu CREATE_DEFFIL
$ retu
$ !
$ ! =0C$ !=20
$ DO_MA:
$ deffil =3D "$CHKLGIDEF.MAR"
$ cmnt1  =3D "; "
$ cmnt2  =3D ""
$ defcmd =3D "$EQU  "
$ asscmd =3D ""
$ endcmd =3D ""
$ prfcmd1 =3D "       .MACRO   $CHKLGIDEF,$GBL"
$ prfcmd2 =3D "       $DEFINI  CHKLGI,$GBL"
$ prfcmd3 =3D "###"
$ pstcmd1 =3D "       $DEFEND  CHKLGI,$GBL,DEF"
$ pstcmd2 =3D "       .ENDM"
$ pstcmd3 =3D "###"
$ len =3D 40
$ gosu CREATE_DEFFIL
$ rtnfil =3D ""
$ libfil =3D "CHKLGI.MLB"
$ gosu CREATE_LIB
$ retu
$ !
$ ! =0C$ !=20
$ DO_PA:
$ deffil =3D "$CHKLGIDEF.PAS"
$ cmnt1  =3D "(* "
$ cmnt2  =3D " *)"
$ defcmd =3D "   "
$ asscmd =3D "=3D"
$ endcmd =3D ";"
$ prfcmd1 =3D "CONST"
$ prfcmd2 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 40
$ gosu CREATE_DEFFIL
$ rtnfil =3D "CHKLGI$RTN.PAS"
$ dclcmd1  =3D "[HIDDEN] TYPE"
$ dclcmd2  =3D "         $UBYTE =3D [BYTE] 0..255;"
$ dclcmd3  =3D "         $UQUAD =3D [QUAD,UNSAFE] RECORD"
$ dclcmd4  =3D "         L0,L1:UNSIGNED; END;"
$ dclcmd5  =3D ""
$ dclcmd6  =3D "[ASYNCHRONOUS,EXTERNAL(CHKLGI)] FUNCTION CHKLGI("
$ dclcmd7  =3D "       USRNAM : [CLASS_S] PACKED ARRAY [$l1..$u1:INTEGER]=
 OF CHAR :=3D %IMMED 0;"
$ dclcmd8  =3D "       LGIDEV : [CLASS_S] PACKED ARRAY [$l2..$u2:INTEGER]=
 OF CHAR :=3D %IMMED 0;"
$ dclcmd9  =3D "       REMINF : [CLASS_S] PACKED ARRAY [$l3..$u3:INTEGER]=
 OF CHAR :=3D %IMMED 0;"
$ dclcmd10 =3D "       PASWD1 : [CLASS_S] PACKED ARRAY [$l4..$u4:INTEGER]=
 OF CHAR :=3D %IMMED 0;"
$ dclcmd11 =3D "       PASWD2 : [CLASS_S] PACKED ARRAY [$l5..$u5:INTEGER]=
 OF CHAR :=3D %IMMED 0;"
$ dclcmd12 =3D "       LGISRC : UNSIGNED :=3D %IMMED 0;"
$ dclcmd13 =3D "       LGITIM : $UQUAD :=3D %IMMED 0;
$ dclcmd14 =3D "       LGIDAY : UNSIGNED :=3D %IMMED 0;"
$ dclcmd15 =3D "       FLAGS : UNSIGNED :=3D %IMMED 0;"
$ dclcmd16 =3D "       %REF INITMLST : ARRAY [$l10..$u10:INTEGER] OF $UBY=
TE :=3D %IMMED 0;
$ dclcmd17 =3D "       %REF OUTITMLST : ARRAY [$l11..$u11:INTEGER] OF $UB=
YTE :=3D %IMMED 0) : INTEGER; EXTERNAL;
$ dclcmd18 =3D "###"
$ gosu CREATE_RTNFIL
$ libfil =3D "PAS$CHKLGI.TLB"
$ gosu CREATE_LIB
$$ retu
$ !
$ ! =0C$ !=20
$ DO_PL:
$ deffil =3D "$CHKLGIDEF.PLI"
$ cmnt1  =3D "/* "
$ cmnt2  =3D " */"
$ defcmd =3D "%replace"
$ asscmd =3D "by"
$ endcmd =3D ";"
$ prfcmd1 =3D "###"
$ pstcmd1 =3D "###"
$ len =3D 45
$ gosu CREATE_DEFFIL
$ rtnfil =3D "CHKLGI$RTN.PLI"
$ dclcmd1  =3D "dcl chklgi entry ("
$ dclcmd2  =3D "   any character(*) optional,        /* usrnam */"
$ dclcmd3  =3D "   any character(*) optional,        /* lgidef */"
$ dclcmd4  =3D "   any character(*) optional,        /* reminf */"
$ dclcmd5  =3D "   any character(*) optional,        /* paswd1 */"
$ dclcmd6  =3D "   any character(*) optional,        /* paswd2 */"
$ dclcmd7  =3D "   fixed bin(31) reference optional, /* lgisrc */"
$ dclcmd8  =3D "   any optional,                     /* lgitim */"
$ dclcmd9  =3D "   fixed bin(31) reference optional, /* lgiday */"
$ dclcmd10 =3D "   fixed bin(31) reference optional, /* flags  */"
$ dclcmd11 =3D "   any reference optional,           /* initmlst */"
$ dclcmd12 =3D "   any reference optional)           /* outitmlst */"
$ dclcmd13 =3D "   returns (fixed bin(31));"
$ dclcmd14 =3D "###"
$ gosu CREATE_RTNFIL
$ libfil =3D "PLI$CHKLGI.TLB"
$ gosu CREATE_LIB
$ retu
$ !
$ ! =0C$ !
$ CREATE_DEFFIL:
$ open/read inf CHKLGIDEF.H
$ open/writ out 'deffil'
$ writ out ""
$ writ out "''cmnt1'Module $CHKLGIDEF''cmnt2'"
$ writ out "''cmnt1'-----------------''cmnt2'"
$ writ out ""
$ n =3D 1
$ L_2:
$ if prfcmd'n' .nes. "###"
$ then
$ writ out prfcmd'n'
$ n =3D n + 1
$ goto L_2
$ endi
$ L_3:
$ read/end=3DE_3 inf rec
$ rec =3D f$edit(rec,"TRIM,COMPRESS,UNCOMMENT")
$ if rec .eqs. "" then goto L_2
$ cmd =3D f$elem(0," ",rec)
$ if cmd .nes. "#define" then goto L_2
$ symb =3D f$elem(1," ",rec)
$ if f$extr(0,2,symb) .eqs. "__" then goto L_2
$ val =3D f$elem(2, " ",rec)
$ outstr =3D defcmd + " " + symb + " " + asscmd + " " + val + endcmd
$ if f$elem(3," ",rec) .eqs. "/*"
$ then
$ cmnt =3D f$elem(1,"*",rec)
$ cmnt =3D f$edit (cmnt, "TRIM")
$ cmnt =3D cmnt1 + cmnt + cmnt2
$ outstr =3D f$fao("!#AS  !AS",len,outstr,cmnt)
$ endi
$ writ out outstr
$ goto L_3
$ E_3:
$ clos inf
$ n =3D 1
$ L_4:
$ if pstcmd'n' .nes. "###"
$ then
$ writ out pstcmd'n'
$ n =3D n + 1
$ goto L_4
$ endi
$ clos out
$ retu
$ !
$ ! =0C$ !
$ CREATE_RTNFIL:
$ open/writ out 'rtnfil'
$ writ out ""
$ writ out "''cmnt1'Module CHKLGI$RTN''cmnt2'"
$ writ out "''cmnt1'-----------------''cmnt2'"
$ writ out ""
$ n =3D 1
$ L_5:
$ if dclcmd'n' .nes. "###"
$ then
$ writ out dclcmd'n'
$ n =3D n + 1
$ goto L_5
$ endi
$ clos out
$ retu
$ !
$ ! =0C$ !
$ CREATE_LIB:
$ if f$pars (libfil,,,"TYPE") .eqs. ".TLB"
$ then libr/crea/text 'libfil'
$ else libr/crea/macr 'libfil'
$ endi
$ if deffil .nes. "" then libr/repl 'libfil' 'deffil'
$ if rtnfil .nes. "" then libr/repl 'libfil' 'rtnfil'
$ retu

=0C---------------------->>> #6: AUDEVT.C <<<----------------------

#ifdef VAXC
#module AUDEVT "BOL-V1.0/OCT-95"
#else
#pragma module AUDEVT "BOL-V1.0/OCT-95"
#endif

/* This routine audits login/login failures.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include descrip	/* Definitions for descriptors */
#include jpidef		/* JPI$_xxx item codes */
#include lib$routines	/* LIB$xxx() routine definitions */
#ifdef __DECC		/* For VAXC, the following module doesn't exist: */
#include nsadef		/* NSA$_xxx audit definitions */
#endif
#include ssdef		/* SS$_xxx system error codes */
#include stdio		/* Standard I/O definitions */
#include string		/* strxxx() function definitions */
#include starlet	/* SYS$xxx() system service definitions */

#include "chklgidef.h"  /* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"  /* LGIBUF structure field definitions */
#include "lgimsgdef.h"  /* LGI$_xxx login status codes */
#include "compdepnd.h"	/* Compiler dependencies (NSA$xxx symbols for VAXC=
) */

typedef struct dsc$descriptor_s dsc;    /* Abbreviation for descriptor st=
ruct.*/

int _nam_2_add (void*,int*);		/* Nodename to address conversion */

/*** =0C ***/

/*** AUDEVT() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 lgistat:  Status of login attempt, by value

 lgi:      Login buffer containing additional information. By reference

 curtim:   Login time (binary). By reference

 lgidev:   Login device (original string, as passed by caller). By refere=
nce

=20
 Return codes:

	The given login status

	Any error code returned by SYS$AUDIT_EVENTW
=20
=0C */

int audevt(int lgistat,struct LGIBUF* lgi,int *curtim,char *lgidev)
{
 /* Auditing is done by the new SYS$AUDIT_EVENT[W] system service. This
    service exists on OpenVMS VAX V6.1 and OpenVMS Alpha V6.2 and higher
    only. If we are running an older version, skip this section and
    return the given login status only. */

#ifdef V6_OK

 char
 *ptr =3D NULL,				/* Aux pointer */
 *ptr1,					/* Aux pointer */
 alarm_name[] =3D "SECURITY",		/* Audit/alarm name */
 trmbuf[128],				/* Output buffer for terminal info */
 parbuf[32];				/* Output buffer for parent name */

 short
 retlen;				/* Return length for lib$getjpi */

 int
 cnt =3D 4,				/* Init count for item list */
 addr =3D 0,				/* Node ID (DECnet address) */
 suprflgs =3D 0,				/* Audit supression flags */
 status,				/* Return status */
 audstat,				/* Audit status */
 type,					/* Event type */
 subtype,				/* Event subtype */
 flags =3D NSA$M_FLUSH|NSA$M_NOEVTCHECK;	/* Audit flags */

 $DESCRIPTOR(nod,ptr);			/* Descriptor for nodename */
 $DESCRIPTOR(par,parbuf);		/* Parent process name */

 struct itmlst itm[14] =3D
 {
  8, NSA$_ALARM_NAME,     alarm_name, 0,
  4, NSA$_EVENT_TYPE,     &type, 0,
  4, NSA$_EVENT_SUBTYPE,  &subtype, 0,
  8, NSA$_TIME_STAMP,     curtim , 0,
 }; =20

 /* First, complete the item list. Set login source (type). Since NSA$C_x=
xx
    symbols are different from CHKLGI/JPI, we must translate them. */

 switch(lgi->L_LGISRC)
 {
  case CHKLGI$_DETACHED: {subtype =3D NSA$C_DETACHED; break;}
  case CHKLGI$_BATCH:    {subtype =3D NSA$C_BATCH;    break;}
  case CHKLGI$_NETWORK:  {subtype =3D NSA$C_NETWORK;  break;}
  case CHKLGI$_DECWINDOWS:
  case CHKLGI$_LOCAL:    {subtype =3D NSA$C_LOCAL;    break;}
  case CHKLGI$_DIALUP:   {subtype =3D NSA$C_DIALUP;   break;}
  case CHKLGI$_REMOTE:   {subtype =3D NSA$C_REMOTE;   break;}
 }
 /* Include the username. This is either a valid username or one
    of the pseudo strings "<login>", "<batch>", "<net>" or "<det>". */

 itm[cnt].size =3D strlen(lgi->T_USRNAM);
 itm[cnt].code =3D NSA$_USERNAME;
 itm[cnt++].info =3D lgi->T_USRNAM;

 /* If this is a detached process, include the 'parent username' as well.
    This is our username. */

 if (lgi->L_LGISRC =3D=3D CHKLGI$_DETACHED)
 {
  status =3D lib$getjpi(&JPI$_USERNAME,0,0,0,&par,&retlen);    /* Get use=
rname */

  if (status !=3D SS$_NORMAL) return status;

  /* The username is returned with blanks filled, so we use
     strcspn to determine the actual length. */

  itm[cnt].size =3D strcspn(parbuf," ");
  itm[cnt].code =3D NSA$_PARENT_USERNAME;
  itm[cnt++].info =3D parbuf;
 }

 /* Include UIC if non-zero value. */

 if (lgi->L_UIC)
 {
  itm[cnt].size =3D 4;
  itm[cnt].code =3D NSA$_SUBJECT_OWNER;
  itm[cnt++].info =3D &lgi->L_UIC;
 }
 else
 {
  /* If no known UIC could be obtained, tell SYS$AUDIT_EVENT to
     suppress this information. */

  suprflgs =3D NSA$M_SUBJECT_OWNER;	/* Do not display UIC info. */

  itm[cnt].size =3D 4;
  itm[cnt].code =3D NSA$_SUPPRESS;
  itm[cnt++].info =3D &suprflgs;
 }
 /* If a login device was supplied, include it. */

 if (lgidev !=3D NULL)
 {
  strcpy(trmbuf,lgidev);

  /* Include the physicl device name as well, unless it is
     the same string as the given login device. */

  if (strcmp(lgidev,lgi->T_PHYDEVNAM))
  {
   strcat(trmbuf,", ");

   strcat(trmbuf,lgi->T_PHYDEVNAM);
  }
  /* Include the access port name, if any. */

  if (strlen(lgi->T_ACCPORNAM))
  {
   strcat(trmbuf,", ");

   strcat(trmbuf,lgi->T_ACCPORNAM);
  }
  /* Setup item item list. */

  itm[cnt].size =3D strlen(trmbuf);
  itm[cnt].code =3D NSA$_TERMINAL;
  itm[cnt++].info =3D trmbuf;
 }
 /* If remote info was given, include it. */

 if (strlen(lgi->T_REMINF))
 {
  ptr =3D strstr(lgi->T_REMINF,"::");

  ptr1 =3D lgi->T_REMINF;
 }
 /* If the access port name of the given terminal includes
    a REMNOD::REMUSR pair, we will include it as well. */
=20
 else if (strlen(lgi->T_ACCPORNAM))
 {
  ptr =3D strstr(lgi->T_ACCPORNAM,"::");

  ptr1 =3D lgi->T_ACCPORNAM;
 }
 /* If we have remote information, include it. */

 if (ptr)
 {
  itm[cnt].size =3D strlen(ptr1) - strlen(ptr);
  itm[cnt].code =3D NSA$_REMOTE_NODENAME;
  itm[cnt].info =3D ptr1;

  /* Setup descriptor for nodename. */

  nod.dsc$w_length =3D itm[cnt].size;
  nod.dsc$a_pointer =3D itm[cnt++].info;

  itm[cnt].size =3D strlen(ptr) - 2;
  itm[cnt].code =3D NSA$_REMOTE_USERNAME;
  itm[cnt].info =3D (char*) ptr+2;

  /* Convert the nodename to a node address. This is done a short
     macro program. Thanks to Wolfgang J. Moeller
     (moeller@gwdvms.dnet.gwdg.de) for showing me how to do this. */
    =20
  status =3D _nam_2_add (&nod, &addr);

  /* Include this information as well. */

  itm[++cnt].size =3D 4;
  itm[cnt].code =3D NSA$_REMOTE_NODE_ID;
  itm[cnt++].info =3D &addr;
 }
 /* In the case of batch, detached and network logins, we don't want to
    display a terminal name, so tell SYS$AUDIT_EVENT to suppress it. */

 switch (lgi->L_LGISRC)
 {
  case CHKLGI$_DETACHED:
  case CHKLGI$_BATCH:
  case CHKLGI$_NETWORK:
  {
   /* If suprflgs is non-zero, there is already an NSA$_SUPPRESS
      entry in the item list. Simply set the approbiate bit in
      'suprflgs'. Otherwise, create a new item entry. */

   if (!suprflgs)
   {
    itm[cnt].size =3D 4;
    itm[cnt].code =3D NSA$_SUPPRESS;
    itm[cnt++].info =3D &suprflgs;
   }
   suprflgs |=3D NSA$M_TERMINAL;	/* Do not display terminal info. */
  }
 }
 /* Now setup and complete the list, depending on the given status. */
=20
 if (lgistat & 1)
 {
  /* Successful login. Update event type. */

  type =3D NSA$C_MSG_LOGIN;

  /* If the status isn't SS$_NORMAL, it is a license-related status
     which we will include as well. */

  if (lgistat !=3D SS$_NORMAL)
  {
   itm[cnt].size =3D 4;
   itm[cnt].code =3D NSA$_FINAL_STATUS;
   itm[cnt++].info =3D &lgistat;
  }
 }
 else
 {
  /* If this a login failure, set the event type and include the
     reason for the failure. */

  if (lgistat !=3D LGI$_EVADE)
  {
   type =3D NSA$C_MSG_LOGFAIL;
  =20
   itm[cnt].size =3D 4;
   itm[cnt].code =3D NSA$_FINAL_STATUS;
   itm[cnt++].info =3D &lgistat;
  }
  else
  {
   /* In the case of break-in evasion, set the type and final status
      accordingly. We also have to include the given password here. */

   type =3D NSA$C_MSG_BREAKIN;
  =20
   itm[cnt].size =3D 4;
   itm[cnt].code =3D NSA$_FINAL_STATUS;
   itm[cnt++].info =3D &lgistat;

   itm[cnt].size =3D strlen(lgi->T_PASSWD);
   itm[cnt].code =3D NSA$_PASSWORD;
   itm[cnt++].info =3D lgi->T_PASSWD;
  }
 }
 /* Mark the current item entry as end. */

 itm[cnt].size =3D itm[cnt].code =3D 0;

 /* Generate the alarm message. It is displayed on all
    operator terminals with the SECURITY class enabled. */

 status =3D sys$audit_eventw (0, flags, itm, &audstat, 0,0);

 /* Return error status. */

 if (status !=3D SS$_NORMAL) return status;

 if (audstat !=3D SS$_NORMAL) return audstat;

 /* Generate the audit message which is included into
    the audit journal file. We must change the
    NSA$_ALARM_NAME item to NSA$_AUDIT_NAME. */

 itm[0].code =3D NSA$_AUDIT_NAME;

 /* In addition, in audit messages, an invalid username must
    be displayed. The invalid name, if given, is stored in
    lgi->T_BADNAM, the item entry pointing to the username has
    the index 4. Just update this entry. */

 if (lgi->T_BADNAM[0])
 {
  itm[4].size =3D strlen(lgi->T_BADNAM);
  itm[4].info =3D lgi->T_BADNAM;
 }
 /* Generate audit message. */

 status =3D sys$audit_eventw (0, flags, itm, &audstat, 0,0);

 /* Return error status. */

 if (status !=3D SS$_NORMAL) return status;

 if (audstat !=3D SS$_NORMAL) return audstat;

 /* That's all. Pass the given login status back to the main routine. */

#endif	/* V6_OK */

 return lgistat;
}

=0C---------------------->>> #7: CHKITM.C <<<----------------------

#ifdef VAXC
#module CHKITM "BOL-V1.0/OCT-95"
#else
#pragma module CHKITM "BOL-V1.0/OCT-95"
#endif

/* This routine processes the input item list (which corresponds to
   the qualifiers given at the Username: prompt) and performs the
   required checks.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include descrip		/* Definitions for descriptors */
#include iacdef			/* Flags for image activation */
#include ssdef			/* SS$_xxx status codes */
#include starlet		/* SYS$xxx() system services */
#include string			/* strxxx() functions */
#include uaidef			/* UAI$M_xxx item codes and flags */

#include "chklgidef.h"		/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"		/* LGIBUF structure field definitions */
#include "lgimsgdef.h"		/* LGI$_xxx login status codes */
#include "compdepnd.h"		/* Compiler-dependend definitions */

typedef struct dsc$descriptor_s dsc;

/*** Aux routine ***/

static int activate(int,dsc*);

/*** =0C ***/

/*** CHKITM() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 lgi:		login buffer, by reference
 initm:		input item list, by reference

=20
 Return codes:

	SS$_NORMAL:	validation ok

	SS$_BADPARAM:	invalid item code or string value too long

	LGI$_CAPTIVE:	no qualifiers allowed in captive accounts

	LGI$_CLIFAIL:	error activating command interpreter

	LGI$_CLITBLFAIL: error activating command interpreter tables

	LGI$_DEFCLI:	CLI-related qualifiers are not allowed

	LGI$_DISRECONNEC: no reconnections allowed

	Note that error codes returned by SYS$IMGACT are converted to
	LGI$_CLIFAIL and LGI$_CLITBLFAIL, respectively.


	NOTE: THE IMAGE ACTIVATION SYSTEM SERVICE USED IN THIS
	      MODULE IS NOT SUPPORTED AND DOCUMENTED OFFICIALY.
	      USE IT ON YOUR OWN RISK.
=0C */

int chkitm(struct LGIBUF* lgi,	/* Buffer containing UAF information */
	   void* initm)
{
 char
 clibuf[40],					/* Buffer for CLI name */
 tabbuf[40];					/* Buffer for CLI table name */

 int
 length,					/* Length field */
 status;					/* Return status */

 $DESCRIPTOR(clidsc,clibuf);			/* Descriptor for CLI */
 $DESCRIPTOR(tabdsc,tabbuf);			/* Descriptor for CLI table */

 struct itmlst *itmptr;				/* Pointer to item list */

 /* Init CLI table name buffer (required for later) */

  tabbuf[0] =3D '\0';

 /* Copy CLI name from UAF record, if it was found therein.
    Otherwise, use "DCL" as default. */

 if (strlen(lgi->T_CLI)) strcpy(clibuf,lgi->T_CLI);

 else strcpy(clibuf,"DCL");

 /* Copy the CLI table name as well. */

 if (strlen(lgi->T_CLITAB)) strcpy(tabbuf,lgi->T_CLITAB);

 /* Process item list. Place pointer to first item. */

 itmptr =3D (struct itmlst*) initm;

 /* Scan the item list and call the approbiate routine. If 'code' =3D 0,
    the end of the list is reached, so return. This is also true, if
    an error status is returned. */

 while(itmptr->code)
 {
  switch(itmptr->code)
  {
   case CHKLGI$_CLI:
   {
    /* This emulates the /CLI=3D qualifier on the command line. The
      account must not have the RESTRICTED or CAPTIVE flags set. */

    if (lgi->L_FLAGS & UAI$M_CAPTIVE || lgi->L_FLAGS & UAI$M_RESTRICTED)
    return LGI$_CAPTIVE;

    /* In addition, CLI-related qualifiers aren't allowed when the
       DEFCLI flag is set. */

    if (lgi->L_FLAGS & UAI$M_DEFCLI) return LGI$_DEFCLI;

    /* The CLI name must not exceed 39 characters. */

    if (itmptr->size < 0 || itmptr->size > 39) return SS$_BADPARAM;

    /* Overwrite default value. */

    strncpy(clibuf,(char*)itmptr->info,itmptr->size);

    clibuf[itmptr->size] =3D '\0';

    break;
   }
   case CHKLGI$_TABLES:
   {
    /* Well, thats the same as for CLI. */

    if (lgi->L_FLAGS & UAI$M_CAPTIVE || lgi->L_FLAGS & UAI$M_RESTRICTED)
    return LGI$_CAPTIVE;

    if (lgi->L_FLAGS & UAI$M_DEFCLI) return LGI$_DEFCLI;

    if (itmptr->size < 0 || itmptr->size > 39) return SS$_BADPARAM;

    /* Update the CLI table name. */

    strncpy(tabbuf,(char*)itmptr->info,itmptr->size);

    tabbuf[itmptr->size] =3D '\0';

    break;
   }
   case CHKLGI$_COMMAND:
   case CHKLGI$_DISK:
   {
    /* These items only simulate the usage of the /COMMAND=3D, /NOCOMMAND
       and /DISK=3D qualifiers. They are allowed unless the CAPTIVE or
       RESTRICTED flags are set. */

    if (lgi->L_FLAGS & UAI$M_CAPTIVE || lgi->L_FLAGS & UAI$M_RESTRICTED)
    return LGI$_CAPTIVE;

    break;
   }
   case CHKLGI$_CONNECT:
   {
    /* This item emulates the usage of /CONNECT. This is allowed unless
       CAPTIVE, RESTRICTED or DISRECONNECT is set. */

    if (lgi->L_FLAGS & UAI$M_CAPTIVE || lgi->L_FLAGS & UAI$M_RESTRICTED)
    return LGI$_CAPTIVE;

    /* Return a specific error code for DISRECONNECT. */

    if (lgi->L_FLAGS & UAI$M_DISRECONNECT) return LGI$_DISRECONNECT;

    break;
   }
   default:
   {
    /* Any other item code is invalid. */

    return SS$_BADPARAM;
   }
  }
  /* Point to next item code and continue. */

  itmptr++;
 }
 /* The item list was processed completely here. The only thing we've
    to do here is to activate the specified or obtain CLI and CLI table.
    If the user has disabled this check, we can return immediately. */

 if (!(lgi->L_IFLAGS & CHKLGI$M_DO_CLI_CHK)) return SS$_NORMAL;

 /* Update CLI descriptor length. */
 =20
 clidsc.dsc$w_length =3D strlen(clibuf);

 /* If no CLI table name was given, use 'cli_name'TABLES as default. */

 if (!strlen(tabbuf))
 {
  strcpy(tabbuf,clibuf);

  strcat(tabbuf,"TABLES");
 }
 tabdsc.dsc$w_length =3D strlen(tabbuf);

 /* Now try to activate the CLI and CLI table. If an error occurs,
    convert it to the approbiate LGI error code. */

 if ((status =3D activate(1,&clidsc)) !=3D SS$_NORMAL) return LGI$_CLIFAI=
L;

 if ((status =3D activate(2,&tabdsc)) !=3D SS$_NORMAL) return LGI$_CLITBL=
FAIL;

 /* All done, return. */

 return SS$_NORMAL;
}

/*** =0C ***/

static int activate(int typ,dsc* imgnam)
{
 /* Activates the given CLI (typ =3D 1) or CLI table (typ =3D 2).

 Input arguments:

 typ:           CLI (1) or CLI table (2), by value
 imgnam:	image name, by descriptor

 Return codes:

	SS$_NORMAL:	validation ok

	LGI$_CLIFAIL:	error activating command interpreter

	LGI$_CLITBLFAIL: error activating command interpreter tables

	Note that all error codes returned by SYS$IMGACT are converted
	to LGI$_CLIFAIL and LGI$_CLITBLFAIL, respectively.
 */

 char
 hdrbuf[1024],				/* Buffer to receive image header */
 defnam1[] =3D "SYS$SYSTEM:.EXE",		/* Default spec for CLI */
 defnam2[] =3D "SYS$SHARE:.EXE";		/* Default spec for CLI table */

 int
 status,				/* Return status */
 flags,					/* Flags for activation */
 inadr[2] =3D {0,0},			/* Input address (P0 space) */
 retadr[2];				/* Return address */

 $DESCRIPTOR (defdsc, defnam1);		/* CLI/CLI table default spec descr. */

 /* Initialize flags. */

 flags =3D IAC$M_NOACT|IAC$M_SHAREABLE|IAC$M_EXPREG|IAC$M_P1MERGE;

 /* Setup correct default image spec. */

 if (typ =3D=3D 2)
 {
  defdsc.dsc$a_pointer =3D defnam2;

  defdsc.dsc$w_length =3D strlen(defnam2); =20
 }
 /* Activate given image. */

 status =3D sys$imgact(imgnam,&defdsc,hdrbuf,flags,inadr,retadr,0,0);
=20
 /* If not success, return LGI-specific error. */

 if (status !=3D SS$_NORMAL) status =3D typ =3D=3D 1 ? LGI$_CLIFAIL : LGI=
$_CLITBLFAIL;

 return status;
}

=0C---------------------->>> #8: CHKLGI.C <<<----------------------

#ifdef VAXC
#module CHKLGI "BOL-V1.0/OCT-95"
#else
#pragma module CHKLGI "BOL-V1.0/OCT-95"
#endif

/* This is the main part of the CHKLGI (check login) routine.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at). */

#include ctype				/* toupper() function */
#include descrip			/* Definitions for descriptors */
#include jpidef				/* JPI$_xxx item codes */
#include lib$routines			/* LIB$xxx() routine definitions */
#include prvdef				/* PRV$_xxx privilege definitions */
#include ssdef				/* SS$_xxx status codes */
#include starlet			/* SYS$xxx() system services */
#include stdlib				/* Standard C library defintions */
#include stdio				/* Standard I/O definitions */
#include string				/* strxxx() functions */
#include uaidef				/* UAI$M_xxx flags */

#include "chklgidef.h"			/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"			/* LGIBUF structure field definitions */
#include "lgimsgdef.h"			/* LGI$_xxx login status codes */
#include "compdepnd.h"			/* Compiler-dependend definitions */

typedef struct dsc$descriptor_s dsc;	/* Abbreviation for descriptor struc=
t.*/

#define C_MAX_USRNAM	12	/* maximum length of a VMS username */
#define C_MAX_LGIDEV	63	/* maximum login device string length */
#define C_MAX_REMINF	63	/* maximum remote information string length */
#define C_MAX_PASSWD	32	/* maximum password length */


/* External routines called by chklgi(): */

int getusr(char*,char*,char*,struct LGIBUF*);	/* Get username */
int chkpwd(char*,int,int*,struct LGIBUF*);	/* Check passwords */
int chktim(int,int*,struct LGIBUF*);		/* Check login times */
int chkquo(struct LGIBUF*);			/* Check login quotas */
int chkitm(struct LGIBUF*,void*);		/* Check items (qualifiers) */
int chklic(struct LGIBUF*);			/* Check licenses */
int intrus(int,struct LGIBUF*);			/* Update intrusion database */
int upduaf(int,struct LGIBUF*,int*);		/* Update UAF record */
int audevt(int,struct LGIBUF*,int*,char*);	/* Audit login event */

/* Internal routines: */

static int setup(dsc*,char*,short);		/* Setup input strings */
int conlgi(struct LGIBUF*,char*);		/* Check for console login */

/* =0C */

/*** Main Entry CHKLGI ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 usrnam.....1-12 character username. By descriptor

 lgidev.....1-63 character login device (terminal). By descriptor

 reminf.....1-63 character remote information. By descriptor

 paswd1.....1-32 primary password. By descriptor

 paswd2.....1-32 secondary password. By descriptor

 lgisrc.....Login source (type). By reference

 lgitim.....Binary login time. By reference

 lgiday.....Login day. By reference=20

 flags......Control flags. By reference

 initmlst...Input item list. By reference

 outitmlst..Output item list. By reference


 Return codes:

	SS$_NORMAL:	all checks performed successfully.

	SS$_NOAUDIT:	AUDIT privilege is required.

	SS$_NOCMKRNL:	CMKRNL privilege is required.

	SS$_SECURITY:	SECURITY privilege is required.

	SS$_NOSYSPRV:	SYSPRV privilege is required.

        SS$_BADPARAM:	a string argument is too long or has
			incorrect format or the given login source
			is invalid or an invalid item code was
			specified.

        SS$_CONFQUAL:	an invalid argument combination (missing
			or conflicting arguments) was given.

	LGI$_ACNTEXC:	too many processes for this account

	LGI$_ACNTEXPIR:	user's account has expired

	LGI$_AUTOLOGIN:	account is for auto-login only
=20
	LGI$_BADDAY:	no login allowed at this day

	LGI$_BADHOUR:	no login allowed at this time

	LGI$_CAPTIVE:	no qualifiers allowed in captive accounts

	LGI$_CLIFAIL:	error activating command interpreter

	LGI$_CLITBLFAIL: error activating command interpreter tables

	LGI$_DECWCAPTIVE: no DECwindows login on captive account

	LGI$_DISRECONNEC: no reconnections allowed

	LGI$_DISUSER:	user's account is disabled

	LGI$_DEFCLI:	CLI-related qualifiers are not allowed

	LGI$_EVADE:	Breakin evasion is in effect

	LGI$_EXLICENSE:	licensed number of system users exceeded

	LGI$_EXQUOTA:	maximum number of interactive users exceeded

	LGI$_INVINPUT:	the name given in the 'lgidev' argument is not
			a (known) terminal or workstation device.

	LGI$_INVPWD:	given password doesn't match

	LGI$_LICNOTREQ:	no license check required for this process

	LGI$_LOGDISABL:	interactive logins are currently disabled

	LGI$_LOGOPRCON:	no VMS or VMSCLUSTER license found, but
			logins are allowed from OPA0:

	LGI$_PWDEXPIR:	password in UAF is marked as (pre-) expired

	LGI$_NOSUCHUSER: the given username wasn't found in the UAF.

	LGI$_NOTVALID:	either there was no correspondig proxy
			(remote/network logins) or no corresponding
			record in the ALF database (local logins).

	LGI$_NOVAXCLUSTER: no (valid) VMSCLUSTER(VAXCLUSTER) license found

	LGI$_RESTRICT	no login allowed from this source

	LGI$_USEREXC:	too many processes for this user
=20

        Any other error codes returned by these system services:

	SYS$AUDIT_EVENTW	SYS$CMKRNL		SYS$GETDVIW
	SYS$GETTIM		SYS$GETUAI		SYS$GRANT_LICENSE
	SYS$HASH_PASSWORD	SYS$IMGACT		SYS$LOOKUP_LICENSE
	SYS$RELEASE_LICENSE	SYS$SCAN_INTRUSION	SYS$SETUAI
	SYS$VERIFY_PROXY

        Any other error codes returned by these RMS services:

        SYS$CONNECT	SYS$CLOSE	SYS$GET 	SYS$OPEN

        Any other error codes returned by these RTL routines:
=20
	LIB$ADD_TIMES		LIB$CVT_FROM_INTERNAL_TIME
	LIB$DAY_OF_WEEK		LIB$GETJPI		LIB$GETSYI

=0C */

int chklgi     (dsc* usrnam,		/* Username */
		dsc* lgidev,		/* Login Device */
		dsc* reminf,		/* Remote Node::User or Server/Port */
		dsc* paswd1,		/* Primary Password */
		dsc* paswd2,		/* Secondary Password */
		int* lgisrc,		/* Login Source (Type) */
		int* lgitim,		/* Login Time */
		int* lgiday,		/* Login Day */
		int* flags,		/* Processing Flags */
		void *initmlst,		/* Input item list */
		void *outitmlst)	/* Output item list */
{
 char
 usrnambuf[14], *usrnamptr =3D NULL,	/* Auxiliary buffers */
 lgidevbuf[66], *lgidevptr =3D NULL,	/* and pointers */
 reminfbuf[66], *reminfptr =3D NULL,
 paswd1buf[32],
 paswd2buf[32];

 int
 tmp,					/* Holds temporary values */
 status,				/* Return status */
 prcsts,				/* Process status bits */
 curtim[2] =3D {0,0},			/* Current time */
 logday =3D 0,				/* Login day */
 privs[2];				/* Process privieges */

 $DESCRIPTOR(usr,usrnambuf);		/* Aux descriptor */

 struct LGIBUF lgi;			/* Buffer to receive UAF information */

 /* =0C */

 /* START OF CHKLGI */
 /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */

 /* Clear buffer to receive UAF info */

 memset(&lgi,0,sizeof(struct LGIBUF));

 /* If a login time was specified by the user, use it. */

 if (lgitim !=3D (int*) 0) memcpy (curtim,lgitim,8);

 /* Otherwise, use current time. */

 if (!curtim[0] || !curtim[1])

 if ((status =3D sys$gettim(curtim)) !=3D SS$_NORMAL) return status;

 /* Obtain privileges to see whether user may call us. */

 if ((status =3D lib$getjpi(&JPI$_PROCPRIV,0,0,privs)) !=3D SS$_NORMAL)
    return status;

 /* We require SYSPRV, CMKRNL and AUDIT privileges at least. */

 if (!(privs[0] & PRV$M_SYSPRV)) return SS$_NOSYSPRV;

 if (!(privs[0] & PRV$M_CMKRNL)) return SS$_NOCMKRNL;

 if (!(privs[1] & PRV$M_AUDIT)) return SS$_NOAUDIT;

 /* Copy the given flags and login source into our work buffer. */

 lgi.L_IFLAGS =3D flags !=3D (int*) 0 ? *flags : 0;

 lgi.L_LGISRC =3D lgisrc !=3D (int*) 0 ? *lgisrc : 3;

 /* If the user specified the CHKLGI$M_NO_AUDIT or CHKLGI$M_INTRUSION
    flags, we require SECURITY privilege in addition. */

 if ((lgi.L_IFLAGS & CHKLGI$M_NO_AUDIT || lgi.L_IFLAGS & CHKLGI$M_INTRUSI=
ON)
      && (!(privs[1] & PRV$M_SECURITY))) return SS$_NOSECURITY;

 /* Setup buffers and store the given strings. */

 if (usrnam !=3D (dsc*) 0)
 {
  if (!(setup(usrnam,usrnambuf,C_MAX_USRNAM)) & 1) return SS$_BADPARAM;

  if (strlen(usrnambuf)) usrnamptr =3D usrnambuf;
 }
 if (lgidev !=3D (dsc*) 0)
 {
  if (!(setup(lgidev,lgidevbuf,C_MAX_LGIDEV)) & 1) return SS$_BADPARAM;

  if (strlen(lgidevbuf)) lgidevptr =3D lgidevbuf;
 }
 if (reminf !=3D (dsc*) 0)
 {
  if (!(setup(reminf,reminfbuf,C_MAX_REMINF)) & 1) return SS$_BADPARAM;

  if (strlen(reminfbuf)) reminfptr =3D reminfbuf;
 }
 /* Pre-init password buffers. */

 paswd1buf[0] =3D '\0';

 if (paswd1 !=3D (dsc*) 0)
 {
  if (!(setup(paswd1,paswd1buf,C_MAX_PASSWD)) & 1) return SS$_BADPARAM;
 }
 paswd2buf[0] =3D '\0';

 if (paswd2 !=3D (dsc*) 0)
 {
  if (!(setup(paswd2,paswd2buf,C_MAX_PASSWD)) & 1) return SS$_BADPARAM;
 }
 /* Since we may audit the password later (in case of breakin evasions),
    setup a template string which is used when no password was supplied.
    This string is eventually overwritten with the incorrect password
    by chkpwd(). */

 strcpy(lgi.T_PASSWD,"<valid>");

/* =0C */

 /* Well, let's go... first, we have to find an entry in the UAF which
    we can use for all checks. This entry may be given in the 'usrnam'
    argument, but may also obtained either by the ALF (automatic login
    facility) or, in the case of network jobs, by proxy processing. The
    routine getusr() will do this job.

    Perform all checks within a pseudo-loop. This allows to abort flow
    of control with a simple 'break' and avoids the use of goto's. */

 while (1)
 {
  /* Obtain username for further checks. */

  status =3D getusr(usrnamptr,lgidevptr,reminfptr,&lgi);

  /* If the status is success, we've found a username and may continue.
     Otherwise, we must do one of the following:

     If the status is a failure code from a system or RMS service, just
     return it to the user.

     Otherwise, it is a LGI$_xxxx error code. Break here, the rest is
     done at the end of this pseudo loop. */

  if (status !=3D SS$_NORMAL)
  {
   if (status < LGI$_FACILITY) return status; /* return VMS error */

   else break;
  }
  /* Update username descriptor for later use. */

  usr.dsc$a_pointer =3D lgi.T_USRNAM;

  usr.dsc$w_length =3D strlen(lgi.T_USRNAM);

/*** =0C ***/

  /* Perform password-related checks. */

  status =3D chkpwd(paswd1buf,0,curtim,&lgi);

  if (status !=3D SS$_NORMAL)
  {
   if (status < LGI$_FACILITY) return status; /* return VMS error */

   else break;
  }
  status =3D chkpwd(paswd2buf,1,curtim,&lgi);

  if (status !=3D SS$_NORMAL)
  {
   if (status < LGI$_FACILITY) return status; /* return VMS error */

   else break;
  }

/* =0C */

  /* Account-related checks. The account must not be disabled or expired.
     These checks are bypassed for system console logins. */

  if (!conlgi(&lgi,lgi.T_USRNAM))			/* If not console */
  {
   if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_DISACC_CHK))	/* and not to skip */
   {
    if (lgi.L_FLAGS & UAI$M_DISACNT)			/* and disabled */
    {
     status =3D LGI$_DISUSER;				/* then abort */

     break;
    }
   }
   /* To see whether the account is expired, compare the given/current
      time with the account expiration time. */
=20
   if (lgi.Q_EXPTIM[1])			/* if exp time set in UAF */
   {
    if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_EXPACC_CHK)) /* and not to skip */
    {
     if (lgi.Q_EXPTIM[1] < curtim[1] || 		/* and expired */
         (lgi.Q_EXPTIM[1] =3D=3D curtim[1] && lgi.Q_EXPTIM[0] < curtim[0]=
))
     {
      status =3D LGI$_ACNTEXPIR;			/* then abort */

      break;
     }
    }
   }
  }
  /* Check for auto-login only account. This is done for interactive
     and network logins only. */

  if (lgi.L_LGISRC >=3D CHKLGI$_INTERACTIVE || lgi.L_LGISRC =3D=3D CHKLGI=
$_NETWORK)
  {
   if (!(lgi.L_IFLAGS & CHKLGI$M_AUTO_LOGIN))	/* If not auto-login */
   {
    if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_ALOGIN_CHK))/* and not to skip */
    {
     if (lgi.L_FLAGS & UAI$M_AUTOLOGIN)		/* and auto-login only */
     {
      status =3D LGI$_AUTOLOGIN;			/* then abort */

      break;
     }
    }
   }
  }
  /* DECwindows logins aren't allowed with captive accounts. */

  if (lgi.L_LGISRC =3D=3D CHKLGI$_DECWINDOWS)		/* If DECwindows login */
  {
   if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_DWICAP_CHK))	/* and not to skip */
   {
    if (lgi.L_FLAGS & UAI$M_CAPTIVE ||			/* and captive or */
	lgi.L_FLAGS & UAI$M_RESTRICTED)			/* restricted */
    {
     status =3D LGI$_DECWCAPTIVE;				/* abort */

     break;
    }
   }
  }

/* =0C */

  /* Login-time and login-source related checks. These checks are bypasse=
d
     for system console logins. */

  if (!conlgi(&lgi,lgi.T_USRNAM))
  {
   /* If login day was specified, use it. */

   if (lgiday !=3D (int*) 0)
   {
    if (*lgiday)
    {
     /* Login day must be in range 1...7 */

     if (*lgiday > 7 || *lgiday < 0) return SS$_BADPARAM;

     logday =3D *lgiday;
    }
   }
   status =3D chktim(logday,curtim,&lgi);

   if (status !=3D SS$_NORMAL)
   {
    if (status < LGI$_FACILITY) return status; /* return VMS error */

    else break;
   }
  }  =20

/* =0C */

  /* Login-quota-related checks. If the interactive login limit is set
     to 0, no further logins are allowed. This is also true if the limit
     is set to <n>, but there are <n> users logged in already. This check
     is made for interactive logins only and is bypassed if the account
     has the default OPER privilege set. */

  if (!(lgi.Q_DEFPRIV[0] & PRV$M_OPER))			/* If not OPER priv */
  {
   if (lgi.L_LGISRC >=3D CHKLGI$_INTERACTIVE)		/* and interactive login *=
/
   {
    if (IJOBCNT > (short) SYS$GW_IJOBLIM)		/* and quota exceeded */
    {
     /* If the limit was set to 0 (SET LOGIN/INTERACTIVE=3D0), return
        LGI$_LOGDISABL; otherwise return LGI$_EXQUOTA. Both checks
	may be suppressed. */

     if (!(short) SYS$GW_IJOBLIM)
     {
      if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_LGIDIS_CHK))
      {
       status =3D LGI$_LOGDISABL;

       break;
      }
     }
     else
     {
      if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_MAXINT_CHK))
      {
       status =3D LGI$_EXQUOTA;

       break;
      }
     }
    }
   }
  }
  /* Check for maximum number of processes for the given username.
     Network jobs are included here, but the first four network
     jobs are "free" (not counted). This check is bypassed if the
     process has the PRC$M_NOACNT bit set in PCB$L_STS.

     In addition, check for maximum number of processes for the
     user's account. Network jobs are not counted here. This check
     is bypassed if the process has the PRC$M_NOACNT bit set in
     PCB$L_STS. */

  if ((status =3D lib$getjpi(&JPI$_STS,0,0,&prcsts)) !=3D SS$_NORMAL) ret=
urn status;

  if (!(prcsts & PCB$M_NOACNT))
  {
   status =3D chkquo(&lgi);

   if (status !=3D SS$_NORMAL)
   {
    if (status < LGI$_FACILITY) return status; /* return VMS error */

    else break;
   }=20
  }

/* =0C */

  /* Check for qualifiers specified in command line. This is emulated by
     the 'initmlst' argument. */

  if (initmlst !=3D (void*) 0)			/* If input items were spec. */
  {
   status =3D chkitm(&lgi,initmlst);		/* check for items */

   if (status !=3D SS$_NORMAL)
   {
    if (status < LGI$_FACILITY) return status; /* return VMS error */

    else break;
   }
  }

/* =0C */

  /* Check for licenses. This check occurs for
     interactive logins only. */
=20
  if (!(lgi.L_IFLAGS & CHKLGI$M_SKP_LIC_CHK))	/* If not to skip */
  {
   if (lgi.L_LGISRC >=3D CHKLGI$_INTERACTIVE)	/* and interactive login */
   {
    status =3D chklic(&lgi);			/* then check for licenses */

    if (!(status & 1))
    {
     if (status < LGI$_FACILITY) return status; /* return VMS error */

     else break;
    }=20
   }
  }
  /* FINISH! All checks done, terminate the pseudo-loop. */

  break;
 }
/* =0C */

 /* Now update the intrusion database, if user requested it. This
    will not occur for batch logins. */

 if (lgi.L_IFLAGS & CHKLGI$M_INTRUSION)
 {
  if (lgi.L_LGISRC !=3D CHKLGI$_BATCH)
  {
   status =3D intrus(status,&lgi);

   if (!(status & 1))

   if (status < LGI$_FACILITY) return status; /* return VMS error */
  }
 }
 /* If user requested it, update UAF record as well. */

 if (lgi.L_IFLAGS & CHKLGI$M_UPDATE_UAF)
 {
  status =3D upduaf(status,&lgi,curtim);

  if (!(status & 1))

  if (status < LGI$_FACILITY) return status; /* return VMS error */
 }
 /* Unless suppressed, audit the event. */

 if (!(lgi.L_IFLAGS & CHKLGI$M_NO_AUDIT))
 {
  status =3D audevt(status,&lgi,curtim,lgidevptr);

  if (!(status & 1))

  if (status < LGI$_FACILITY) return status; /* return VMS error */
 }
 /* Finally, if requested by the user, return UAF information, as specifi=
ed
    in the 'outitmlst' argument. */

 if (outitmlst !=3D (void*) 0)
 {
  tmp =3D sys$getuai (0,0,&usr,outitmlst,0,0,0);

  if (tmp !=3D SS$_NORMAL) return tmp;	/* Return getuai error */
 }
 return status;				/* Otherwise, return actual status */
}

/* =0C */

static int setup(dsc *val,char *buf, short maxlength)
{
 /* Copy string from descriptor to private buffer and convert it
    to uppercase. Also check for maximum allowed length.
    Return 1, if ok, else 0. */

 if (val->dsc$w_length > maxlength) return 0;

 strncpy(buf,val->dsc$a_pointer,val->dsc$w_length);

 buf[val->dsc$w_length] =3D '\0';

 while (*buf)
 {
  *buf =3D toupper(*buf);

  buf++;
 }
 return 1;
}

/* =0C */

int conlgi(struct LGIBUF *lgi,char *usrnam)
{
/* Returns true, id console login occurs, else false. */

 if (!(strcmp(usrnam,"SYSTEM")) &&
     !(strcmp(lgi->T_PHYDEVNAM,"_OPA0:"))) return 1;

 else return 0;
}

=0C---------------------->>> #9: CHKLIC.C <<<----------------------

#ifdef VAXC
#module CHKLIC "BOL-V1.0/OCT-95"
#else
#pragma module CHKLOC "BOL-V1.0/OCT-95"
#endif

/* This routine checks for required licenses to perform
   interactive logins.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include descrip	/* Descriptor definitions */
#include lib$routines	/* LIB$ RTL function definitions */
#ifdef __DECC		/* The following two modules don't exists in VAXC TLB */
#include licensedef	/* LICENSE$_xxxx license status codes */
#include lmfdef		/* LMF$_ license facility constants */
#endif
#include ssdef		/* SS$_xxx system status codes */
#include starlet	/* SYS$_xxx system service definitions */
#include string		/* strxxx() function definitions */
#include syidef		/* SYI$_xxx item code definitions */
#include uaidef		/* UAI$M_xxx item codes and flahs */

#include "chklgidef.h"	/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"  /* LGIBUF structure field definitions */
#include "lgimsgdef.h"  /* LGI$_xxx login status codes */
#include "compdepnd.h"	/* Compiler dependencies */

typedef struct dsc$descriptor_s dsc;

/* Define platform-depending license names and values.

   We define all licenses separately, even if some of them currently
   have the same name on VAX and Alpha. This will make changes in
   the future easier. */

#ifdef __ALPHA
#define VMSLIC1 "OPENVMS-ALPHA"
#define VMSLIC2 "OPENVMS-ALPHA-USER"
#define CLULIC1 "VMSCLUSTER"
#define CLULIC2 "VMSCLUSTER-CLIENT"
#else
#define VMSLIC1 "VAX-VMS"
#define VMSLIC2 "BASE-VMS-250136"
#define CLULIC1 "VAXCLUSTER"
#define CLULIC2 "VMSCLUSTER-CLIENT"
#endif

/* =0C */

/*** CHKLIC() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

   lgi:  Login buffer containing additional information. By reference

   Return codes:

        SS$_NORMAL:    	license validation ok

	LGI$_LOGOPRCON:	no VMS or VMSCLUSTER license found, but
			logins are allowed from OPA0:

	LGI$_LICNOTREQ: no license check required for this process
			(DECwindows logins only)

	LGI$_EXLICENSE:	licensed number of system users exceeded

	LGI$_NOVAXCLUSTER: no (valid) VMSCLUSTER(VAXCLUSTER)
			license found

	Any other error code returned by:

	o - System services SYS$GRANT_LICENSE, SYS$LOOKUP_LICENSE
	o _ RTL routine: LIB$GETSYI

	Note that the following LMF_xxx codes are converted in
	this way:

	Status Code		License		Conversion
	---------------------------------------------------------
	LMF$_EXCEEDED		VMS		LGI$_EXLICENSE
	All LMF error codes 	VMSCLUSTER	LGI$_NOVAXCLUSTER


	NOTE: THE LICENSE-RELATED SYSTEM SERVICES USED IN THIS
	      MODULE ARE NOT SUPPORTED AND DOCUMENTED OFFICIALY.
	      USE IT ON YOUR OWN RISK.
=0C */

int chklic(struct LGIBUF *lgi)		/* Login buffer */
{
 int
 tmp,					/* Temp return status */
 status,				/* Return Status */
 contxt[4];				/* License context buffer */

 $DESCRIPTOR (vms_lic1,VMSLIC1);	/* Name of first VMS license */
 $DESCRIPTOR (vms_lic2,VMSLIC2);	/* Name of second VMS license */
 $DESCRIPTOR (clu_lic1,CLULIC1);	/* Name of first cluster license */
 $DESCRIPTOR (clu_lic2,CLULIC2);	/* Name of second cluster license */

 $DESCRIPTOR (vms_dal,"VMS-DAAL");	/* VMS DAAL license name */
 $DESCRIPTOR (prc_nam,"DEC");		/* Producer name */

 struct itmlst itm[3] =3D 		/* item list for license system serv. */
 {
  4,LMF$_PROD_VERSION,&VMS$GL_LICENSE_VERSION,0,
  8,LMF$_PROD_DATE,&VMS$GQ_LICENSE_DATE,0,
  0,0};

 /* Check for either primary or secondary VMS license. We use
    SYS$GRANT_LICENSE here since we don't want to include license
    groups in the check. */

 status =3D sys$grant_license(&vms_lic1,&prc_nam,contxt,itm);

 /* If status is O.K., release the license. */

 if (status =3D=3D SS$_NORMAL) tmp =3D sys$release_license(contxt);

 /* Otherwise, check secondary license. */

 else
 {
  status =3D sys$grant_license(&vms_lic2,&prc_nam,contxt,itm);

  if (status =3D=3D SS$_NORMAL) tmp =3D sys$release_license(contxt);
 }
 /* Finally, if this is a captive account and there is a VMS-DAAL
    license loaded, allow the login as well. Since this license
    may be part of a group, we use now SYS$LOOKUP_LICENSE. */

 if (status !=3D SS$_NORMAL)
 {
  if (lgi->L_FLAGS & UAI$M_CAPTIVE)

  status =3D sys$lookup_license(&vms_dal,itm,&prc_nam,
			      &LMF$M_RETURN_FAILURES,0,0);
 }
 if (status !=3D SS$_NORMAL)
 {
  /* If there is no valid VMS license, but the user's terminal
     is the console, we allow logins as well, but we will return
     a different status. */

  if (!(strcmp(lgi->T_PHYDEVNAM,"_OPA0:"))) return LGI$_LOGOPRCON;

  /* If this is a DECwindows login, return LGI$_LICNOTREQ. */

  if (lgi->L_LGISRC =3D=3D CHKLGI$_DECWINDOWS) return LGI$_LICNOTREQ;

  /* No license is available - return status now. We convert LICENSE$_EXC=
EEDED
     ("attempted usage exceeds active license limits") to the login-speci=
fic
     code LGI$_EXLICENSE ("licensed number of system users exceeded"). */

  return status =3D=3D LICENSE$_EXCEEDED ? LGI$_EXLICENSE : status;
 }
 /* If this system is part of a VMScluster, we need a cluster license as
    well. Otherwise, we can return immediately. */

 if ((status =3D lib$getsyi(&SYI$_CLUSTER_MEMBER,&tmp)) !=3D SS$_NORMAL)
 return status;

 if (!tmp) return SS$_NORMAL;

 /* Well, its a cluster, so there must be a cluster license as well. */

 status =3D sys$lookup_license(&clu_lic1,itm,&prc_nam,&LMF$M_RETURN_FAILU=
RES,0,0);

 if (status !=3D SS$_NORMAL)
 status =3D sys$lookup_license(&clu_lic2,itm,&prc_nam,&LMF$M_RETURN_FAILU=
RES,0,0);

 /* If O.K., we can return. */

 if (status =3D=3D SS$_NORMAL) return status;

 /* If the login attempt occurs on the console, grant it, but return
    a different status. */

 if (!(strcmp(lgi->T_PHYDEVNAM,"_OPA0:"))) return LGI$_LOGOPRCON;

 /* If this is a DECwindows login, return LGI$_LICNOTREQ. */

 if (lgi->L_LGISRC =3D=3D CHKLGI$_DECWINDOWS) return LGI$_LICNOTREQ;

 /* Otherwise, no login may occur. Convert all LMF-specific error codes
    to the single login code LGI$_NOVAXCLUSTER ("DEC VMSCLUSTER license i=
s
    not active"). */

 return LGI$_NOVAXCLUSTER;
}

=0C---------------------->>> #10: CHKPWD.C <<<----------------------

#ifdef VAXC
#module CHKPWD "BOL-V1.0/OCT-95"
#else
#pragma module CHKPWD "BOL-V1.0/OCT-95"
#endif

/* This routine validates a given password against the password
   stored the UAF and against its expiration information.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include descrip    	/* Definitions for descriptors */
#include lib$routines	/* LIB$xxx RTL routines */
#include libdef		/* LIB$_xxxx status codes */
#include ssdef		/* SS$_xxx system status codes */
#include starlet	/* SYS$xxx() system service definitions */
#include string		/* strxxx() functions */
#include uaidef		/* UAI$_xxx item codes and flags */

#include "chklgidef.h"	/* CHKLGI$_xxx definitions */
#include "lgibufdef.h"  /* LGIBUF structure field definitions */
#include "lgimsgdef.h"  /* LGI$_xxx login status codes */
#include "compdepnd.h"	/* Compiler/platform depencies */

typedef struct dsc$descriptor_s dsc;

/* External routines */

int conlgi(struct LGIBUF*,char*);

/* =0C */

/*** CHKPWD() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:
=20
 pwd:  1-32 character, user-supplied password. By reference.

 cnt:  Password selector (0=3Dprimary, 1=3Dsecondary password). By value

 tim:  Binary time used for expiration checks. By reference

 lgi:  Login buffer containing additional information. By reference


 Return codes:

	SS$_NORMAL:    password validation ok

	SS$_BADPARAM:  given password is too long

	LGI$_INVPWD:   given password doesn't match

	LGI$_PWDEXPIR: password in UAF is marked as (pre-) expired

	Any other error code returned by:

	o - System Service: SYS$HASH_PASSWORD
	o - RTL Routine: LIB$ADD_TIMES
		=09
=0C */

int chkpwd(char* paswd,		/* User-supplied password */
	   int  cnt,		/* 0 =3D primary password, 1 =3D sec. password */
	   int* tim,		/* Time used for expiration check */
	   struct LGIBUF* lgi)	/* Buffer containing UAF information */
{
 int
 status,			/* Return status */
 retpwd[2],			/* Hashed password */
 restim[2];			/* Resultant time */

 $DESCRIPTOR(usr,lgi->T_USRNAM);

 $DESCRIPTOR(pwd,paswd);

 /* Update descriptor length for username and password. */

 usr.dsc$w_length =3D strlen(lgi->T_USRNAM);

 pwd.dsc$w_length =3D strlen(paswd);

 /* If a password was given, check it. */

 if (paswd[0])
 {
  /* Ensure that the given password isn't too long. */

  if (pwd.dsc$w_length > UAI$C_MAX_PWD_LENGTH) return SS$_BADPARAM;

  /* Validate user's password. Skip if the password isn't set in the UAF.=
 */

  if (lgi->Q_PWD[cnt][0] && lgi->Q_PWD[cnt][1])
  {   =20
   /* Encrypt the password. */

   status =3D sys$hash_password(&pwd,lgi->B_PWDENC[cnt],lgi->W_PWDSALT,&u=
sr,retpwd);

   if (status !=3D SS$_NORMAL) return status;

   /* Now compare hashed password from UAF with password given by the use=
r.
      If they don't match, abort. */

   if (lgi->Q_PWD[cnt][0] !=3D retpwd[0] && lgi->Q_PWD[cnt][1] !=3D retpw=
d[1])
   {
    /* Copy the incorrect password for later auditing. */

    strcpy(lgi->T_PASSWD,paswd);

    /* and return. */

    return LGI$_INVPWD;
   }
  }
 }
 /* Ensure that the password isn't expired. If this is a system-console
    login, a detached login or the user has disabled password expiration
    checks, bypass these checks and return immediately. */

 if (conlgi(lgi,lgi->T_USRNAM) || 		/* System-console login */
     lgi->L_LGISRC =3D=3D CHKLGI$_DETACHED ||	/* Detached login */
     lgi->L_IFLAGS & CHKLGI$M_SKP_EXPPWD_CHK)	/* Disabled by user */
 return SS$_NORMAL;

 /* Now check the primary or secondary password, depending on
    the given password selector.

    If the user attempted to login with its password expired or
    the password was marked as expired by the system manager with
    the AUTHORIZE utility, the UAI$M_PWDx_EXPIRED flags are set.
    If the password was marked as pre-expired, the flags aren't
    set, but the 'last modification time' in the UAF contains -1. */

 if (!cnt)					/* Check for primary password */
 {
  if (lgi->L_FLAGS & UAI$M_PWD_EXPIRED ||	/* If primary password exp */
     (lgi->Q_PWDDAT[0][0] =3D=3D -1 &&		/* or was marked */
      lgi->Q_PWDDAT[0][1] =3D=3D -1))		/* as pre-expired */

  return LGI$_PWDEXPIR;				/* Abort. */
 }
 else						/* Or secondary password */
 {
  if (lgi->L_FLAGS & UAI$M_PWD2_EXPIRED ||	/* If sec. password exp */
     (lgi->Q_PWDDAT[1][0] =3D=3D -1 &&		/* or was marked */
      lgi->Q_PWDDAT[1][1] =3D=3D -1))		/* as pre-expired */

  return LGI$_PWDEXPIR;				/* Abort. */
 }
 /* Otherwise, we must perform the expiration check ourself:

    o - add the expiration time to the time of the last pwd change
    o - the resultant value must be greather than the given time. */

 if (lgi->Q_PWDTIM[1])				/* Only if an expiration time */
 {						/* was specified in the UAF */
  status =3D lib$add_times(lgi->Q_PWDDAT[cnt],lgi->Q_PWDTIM,restim);

  if (status !=3D LIB$_NORMAL) return status;

  /* Compare this time with the current time. */

  if (restim[1] < tim[1] ||
     (restim[1] =3D=3D tim[1] && restim[0] < tim[0]))

  return LGI$_PWDEXPIR;
 }
 /* Everything OK. */

 return SS$_NORMAL;
}

=0C---------------------->>> #11: CHKQUO.C <<<----------------------

#ifdef VAXC
#module CHKQUO "BOL-V1.0/OCT-95"
#else
#pragma module CHKQUO "BOL-V1.0/OCT-95"
#endif

/* This routine checks the MAXJOBS and MAXACCTJOBS quotas.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include ssdef			/* SS$_xxx system status codes */
#include starlet		/* SYS$xxx() system service definitions */
#include string			/* strxxx() functions */

#include "chklgidef.h"		/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"		/* LGIBUF structure field definitions */
#include "lgimsgdef.h"		/* LGI$_xxx login status codes */

int _getquo();			/* Kernel-mode routine to obtain values
				   for quota checks */
/*** =0C ***/

/*** CHKQUO() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

   lgi:  Login buffer containing further information. By reference


   Return codes:

	SS$_NORMAL:    account quota validation ok

	LGI$_USEREXC:  too many processes for this user

	LGI$_ACNTEXC:  too many processes for this account

	Any other error code returned by:

	o - System Service: SYS$CMKRNL

=0C */

int chkquo(struct LGIBUF* lgi)	/* Buffer containing UAF information */
{
 char
 accnam[8],			/* blank-filled account name */
 usrnam[12];			/* blank-filled username */

 int
 status,			/* Return status */
 acccnt,			/* # of processes with this account name */
 usrcnt,			/* # of processes with this username */
 netusrcnt;			/* # of network jobs with this username */

 struct				/* Kernel-mode routine parameters */
 {
  int prmcnt;
  char* accptr;
  char* usrptr;
  void* cntptr1;
  void* cntptr2;
  void* cntptr3;
 } k_prm;

 /* If the MAXJOBS and MAXACCTJOBS are both zero (user has no login
    quota limits), we can skip all further checks. */

 if (!lgi->W_MAXJOBS && !lgi->W_MAXACCJOBS) return SS$_NORMAL;

 /* Obtain the current # of processes for username and account name.
    This must be done in kernel mode. First, initialize the structure
    passed as parameter to the kernel-mode routine. */

 k_prm.prmcnt =3D 5;		/* 5 parameters */
 k_prm.accptr =3D accnam;		/* Account name */
 k_prm.usrptr =3D usrnam;		/* Username */
 k_prm.cntptr1 =3D &acccnt;	/* Curr # of proc with this account name */
 k_prm.cntptr2 =3D &usrcnt;	/* Curr # of proc with this username */
			   	/* (excluding network jobs) */
 k_prm.cntptr3 =3D &netusrcnt;	/* Curr # of network jobs with this userna=
me */

 /* Prepare the blank-filled strings. */

 memset (accnam,0x20,sizeof(accnam));

 memcpy (accnam,lgi->T_ACCNAM,strlen(lgi->T_ACCNAM));

 memset (usrnam,0x20,sizeof(usrnam));

 memcpy (usrnam,lgi->T_USRNAM,strlen(lgi->T_USRNAM));

 /* Call the kernel-mode routine to obtain the values. */

 if ((status =3D sys$cmkrnl(_getquo,&k_prm)) !=3D SS$_NORMAL) return stat=
us;

 /* Since we simulate a new logon with a new process, we must
    increment the counters for it. */

 acccnt++;

 if (lgi->L_LGISRC =3D=3D CHKLGI$_NETWORK) netusrcnt++;

 else usrcnt++;=20

 /* By convention, the first four network jobs aren't counted. */

 switch (netusrcnt)
 {
  case 0: {netusrcnt =3D 0; break;}

  case 1:
  case 2:
  case 3:
  case 4: {netusrcnt =3D 1; break;}

  default: netusrcnt -=3D 4;
 }

 /* The total number of processes with the given username is the sum of
    usrcnt and the updated netusrcnt. */

 usrcnt +=3D netusrcnt;

 /* Now check for expired quotas, unless the user has disabled it. */

 if (!(lgi->L_IFLAGS & CHKLGI$M_SKP_MAXACC_CHK))
 {
  if (lgi->W_MAXACCJOBS && acccnt > lgi->W_MAXACCJOBS) return LGI$_ACNTEX=
C;
 }
 if (!(lgi->L_IFLAGS & CHKLGI$M_SKP_MAXUSR_CHK))
 {
  if (lgi->W_MAXJOBS && usrcnt > lgi->W_MAXJOBS) return LGI$_USEREXC;
 }
 /* OK, that's all. */

 return SS$_NORMAL;
}

=0C---------------------->>> #12: CHKTIM.C <<<----------------------

#ifdef VAXC
#module CHKTIM "BOL-V1.0/OCT-95"
#else
#pragma module CHKTIM "BOL-V1.0/OCT-95"
#endif

/* This routine validates login days, login times and login sources.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include lib$routines		/* LIB$xxx RTL routines */
#include libdef			/* LIB$_xxxx status codes */
#include libdtdef		/* LIB$K_xxx date/time definitions */
#include ssdef			/* SS$_xxx system status codes */

#include "chklgidef.h"		/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"		/* LGIBUF structure field definitions */
#include "lgimsgdef.h"		/* LGI$_xxx login status codes */
#include "compdepnd.h"		/* Compiler-dependend declarations */

#define EXE$M_EXPLICITP 0x00080000	/* SET DAY/PRIMARY was done */
#define EXE$M_EXPLICITS 0x00040000	/* SET DAY/SECONDARY was done */

/*** =0C ***/

/*** CHKTIM() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 lday:  Login day, by value (0 =3D not specified)

 ltim:  Login time, by reference

 lgi:   Login buffer containing additional information. By reference


 Returns codes:

	SS$_NORMAL:    time validation ok

	LGI$_BADHOUR:  no login allowed at this time

	LGI$_BADDAY:   no login allowed at this day

	LGI$_RESTRICT: no login allowed from this source

	Any other error code returned by:

	o - RTL Routines: LIB$CVT_FROM_INTERNAL_TIME, LIB$DAY_OF_WEEK
=09
=0C */

int chktim(int lday,		/* Login day */
	   int* ltim,		/* Binary time */
	   struct LGIBUF* lgi)	/* Buffer containing UAF information */
{
 int
 status,		/* Return status */
 typ,			/* Login type */
 day,			/* Login day */
 hour,			/* Hour of day */
 tmp,			/* Auxiliary value */
 s_day,			/* 1 if sec. day, else 0 */
 h_fld;			/* Login hour bit field */

 /* These checks are entirely bypassed for detached processes. */

 if (lgi->L_LGISRC =3D=3D CHKLGI$_DETACHED) return SS$_NORMAL;

 /* Handle DECwindows logins like local logins. */

 typ =3D lgi->L_LGISRC =3D=3D CHKLGI$_DECWINDOWS ? CHKLGI$_LOCAL : lgi->L=
_LGISRC;

 /* Get login day. If specified, use it. */

 if (lday) day =3D lday;

 /* Otherwise, use given time to compute the current day. */

 else if ((status =3D lib$day_of_week(ltim,&day)) !=3D SS$_NORMAL) return=
 status;

 /* Get current hour. */

 status =3D lib$cvt_from_internal_time(&LIB$K_HOUR_OF_DAY,&hour,ltim);

 if (status !=3D LIB$_NORMAL) return status;

 /* Determine whether today is a primary or secondary day. If the
    operator has established this manually (SET DAY command), this
    overrides any setups in the UAF.

    The system marks this by setting bit EXE$M_EXPLICITP in EXE$GL_FLAGS
    and, if SET DAY/SECONDARY was issued, also setting bit
    EXE$M_EXPLICITS. */

 if (EXE$GL_FLAGS & EXE$M_EXPLICITP)
 {
  if (EXE$GL_FLAGS & EXE$M_EXPLICITS) s_day =3D 1;

  else s_day =3D 0;
 }
 else
 {
  /* Obtain this information from UAF. Convert day number to bit value. *=
/
    =20
  tmp =3D 1 << (day-1);=20

  /* If the approbiate bit isn't set in the day vector (UAI$_PRIMEDAYS),
     it's a primary day, else it's a secondary day. */

  if (tmp & lgi->L_PRIMDAYS) s_day =3D 1;

  else s_day =3D 0;
 }
 /* Select the required login bit field. They were stored by getusrnam()
    in the following order in an array of longwords:

    0: network, primary
    1: network, secondary
    2: batch, primary
    3: batch, secondary
    4: local, primary
    5: local, secondary
    6: dialup, primary
    7: dialup, secondary
    8: remote, primary,
    9: remote, secondary

    This allows us easily to obtain the approbiate field by computing
    the index in the array: (typ*2) - 2 + s_day. */

 tmp =3D typ*2 - 2;

 h_fld =3D lgi->L_ACCESS[tmp+s_day];

 /* Now check for login source, day and time. Note that the caller
    can disable one or all of these checks.

    If the bit field is 0, there is no login restriction. */

 if (!h_fld) return SS$_NORMAL;

 /* A value of 0x00FFFFFF means that the login is disabled for the
    entire day. If _both_ vectors (primary and secondary day) have
    this value, the login is disabled for the given source and we
    must return LGI$_RESTRICT to indicate this. */

 if (!(lgi->L_IFLAGS & CHKLGI$M_SKP_SRC_CHK))		/* Skip if suppressed */
 {
  if (lgi->L_ACCESS[tmp] =3D=3D 0x00FFFFFF &&
      lgi->L_ACCESS[tmp+1] =3D=3D 0x00FFFFFF) return LGI$_RESTRICT;
 }
 /* If the current vector has the value 0x00FFFFFF, the login is
    entirely disabled on given day. */

 if (!(lgi->L_IFLAGS & CHKLGI$M_SKP_DAY_CHK))		/* Skip if suppressed */
 {
  if (h_fld =3D=3D 0x00FFFFFF) return LGI$_BADDAY;
 }
 /* Check whether the login is disabled at the given hour.

    If necessary, shift the access bits. We always want a
    value beetween 0 and 7. */

 if (hour > 15)			/* For 16:00 - 23:00 */
 {
  h_fld =3D h_fld >> 16;

  hour =3D hour - 16;
 }
 if (hour > 7)			/* For 8:00 - 15:00 */
 {
  h_fld =3D h_fld >> 8;

  hour =3D hour - 8;
 }
 /* Compute the right hour bit. */

 tmp =3D 1 << hour;

 /* If the correspondig bit is set, access is denied for the hour.
    If the user requested it, skip this check. */

 if (!(lgi->L_IFLAGS & CHKLGI$M_SKP_HOUR_CHK))
 {
  if (tmp & h_fld) return LGI$_BADHOUR;
 }
 /* All done. */

 return SS$_NORMAL;
}

=0C---------------------->>> #13: GETUSR.C <<<----------------------

#ifdef VAXC
#module GETUSR "BOL-V1.0/OCT-95"
#else
#pragma module GETUSR "BOL-V1.0/OCT-95"
#endif

/* This routine returns an UAF record according some input criteria and
   databases (SYSALF and NET[$]PROXY).

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#include dcdef		/* DC$_xxx device class constants */
#include descrip	/* Definitions for descriptors */
#include dvidef		/* DVI$_xxx item codes */
#include lib$routines	/* LIB$ RTL function definitions */
#include psldef		/* PSL$C_xxxx process status definitions */
#include rms		/* RMS (FAB, RAB) definitions and status codes */
#include ssdef		/* SS$_xxx system status codes */
#include starlet	/* SYS$xxx() system service definitions */
#include string		/* strxxx() function definitions */
#include syidef		/* SYI$_xxx item codes */
#include ttdef		/* TT$M_xxx bit names */
#include uaidef		/* UAI$_xxx item codes */

#include "chklgidef.h"	/* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"	/* LGIBUF structure field definitions */
#include "lgimsgdef.h"	/* LGI$_xxx login status codes */
#include "compdepnd.h"	/* Compiler-dependend definitions */

/* ALF record definitions */

#define ALF$C_LENGTH 128	/* Length of record in ALF database */
#define ALF$T_DEVNAME 0		/* Relative position of terminal/port name */
#define ALF$T_USERNAME 63	/* Relative position of associated username */

/* Auxilliary routines called by getusr(): */

static int gettrm(char*,int,char*,char*); /* Get terminal attributes */
static int getalf(char*,char*);		  /* Get user from ALF database */
static int getprx(char*,char*,char*);	  /* Get user via proxy processing =
*/
static int getuai(char*,struct LGIBUF*);  /* Get information from UAF */

/* External routines: */

int conlgi(struct LGIBUF*,char*);	  /* Check for console login */

/* =0C */

/*** GETUSR() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 usrnam: a 1-12 character, zero-terminated string containing a
	 valid VMS username. By reference.
=20
 lgidev: a 1-64 character, zero-terminated string containing the name
	 of a valid, existing terminal or a logical name pointing to
	 this terminal. By reference

 reminf: a 1-256 character, zero-terminated string containing remote
	 information, in the format "REMNOD::REMUSR". By reference.

 lgi:    the login buffer (buffer to receive information about the user
	 whose account was determined by this routine). By reference


 Return codes:

	SS$_NORMAL:   information about the given or obtainend user
		      was successfully returned.

	SS$_BADPARAM: The login source is invalid or the 'reminf'
		      string is not in the "REMINF::REMUSR" format.

	SS$_CONFQUAL: an invalid argument combination (missing
		      or conflicting arguments) was given.

	LGI$_FILEACC: error accessing the system authorization file.

	LGI$_NOSUCHUSER: the given username wasn't found in the UAF.

	LGI$_NOTMODEM: remote modem not wired correctly

	LGI$_NOTVALID:	either there was no correspondig proxy
			(remote/network logins) or no corresponding
			record in the ALF database (local logins).

	LGI$_INVINPUT: the name given in the 'lgidev' argument is not
		       a (known) terminal or workstation device.

	Any other error code returned by:

	o - System Services: SYS$GETDVI, SYS$GETUAI, SYS$VERIFY_PROXY
	o - RMS Services: SYS$OPEN, SYS$CONNECT, SYS$GET, SYS$CLOSE

 =0C */

int getusr(char* usrnam, 	/* Username */
	   char* lgidev,	/* Login Device (terminal) */
	   char* reminf,	/* Remote Node::User */
	   struct LGIBUF* lgi)  /* Login Buffer */
{
 char
 retusr[14],			/* VMS username returned by ALF or proxy */
 *ptr;				/* auxiliary pointer */

 int
 status,			/* Return status */
 trmstat =3D SS$_NORMAL;		/* Return status of gettrm() */

 /* =0C */

 /* Copy the remote information into the 'reminf' field. This information=
 is
    used later for auditing processing. */

 if (reminf !=3D NULL) strcpy(lgi->T_REMINF,reminf);

 /* Copy a username default string into the 'usrnam' field. This default
    is used later for auditing if no valid user could be found. We'll
    assume interactive login here. The default is changed as needed. It
    is updated with a valid username, as sonn as one can be found. */

 strcpy(lgi->T_USRNAM,"<login>");

 /* If a terminal was given in the 'lgidev' arg, translate it into physic=
al
    name, and if available, obtain the access port name. */
   =20
 if (lgidev !=3D NULL)
 {
  if ((trmstat =3D gettrm(lgidev,lgi->L_LGISRC,lgi->T_PHYDEVNAM,
			lgi->T_ACCPORNAM)) !=3D SS$_NORMAL)
  {
   /* If an error other than LGI$_INVINPUT is returned, pass it
      immediately. */

   if (trmstat !=3D LGI$_INVINPUT) return trmstat;
  }
 }
 /* See whether the given username was "DEFAULT". This string is reserved
    for the AUTHORIZE utility's default account. If it was given, abort
    immediately. */

 if (usrnam !=3D NULL)
 {
  if (!(strcmp(usrnam,"DEFAULT"))) return LGI$_NOSUCHUSER;
 }
 /* Ensure that the 'reminf' string contains a REMNOD::REMUSR pair. */

 if (reminf !=3D NULL)
 {
  ptr =3D strstr(reminf,"::");

  if (ptr =3D=3D NULL) return SS$_BADPARAM;
 }
 /* Now process the different login sources. */

 switch(lgi->L_LGISRC)
 {
  /* =0C */

  case CHKLGI$_BATCH:
  {
   /* For this login source, a valid username must be supplied and all
      other arguments must be omitted. */

   if (usrnam =3D=3D NULL || lgidev !=3D NULL || reminf !=3D NULL) return=
 SS$_CONFQUAL;

   /* Change the default username string to indicate batch login. */

   strcpy(lgi->T_USRNAM,"<batch>");

   /* Get information about this user. */

   return getuai(usrnam,lgi);
  }
  /* =0C */

  case CHKLGI$_DETACHED:
  {
   /* Change the default username string to indicate a detached login. */

   strcpy(lgi->T_USRNAM,"<det>");

   /* The rest is common with CHKLGI$_DECWINDOWS. */
  }
  case CHKLGI$_DECWINDOWS:
  {
   /* This is the same as CHKLGI$_BATCH, except that a 'lgidev' argument =
is
      allowed. */

   if (usrnam =3D=3D NULL || reminf !=3D NULL) return SS$_CONFQUAL;

   /* Get information about this user. */

   status =3D getuai(usrnam,lgi);

   /* If an error occured, return it. */

   if (status !=3D SS$_NORMAL) return status;

   /* In case of DECwindows logins, if a login device was specified,=20
      check for valid device class. */

   if (lgi->L_LGISRC =3D=3D CHKLGI$_DECWINDOWS && trmstat =3D=3D LGI$_INV=
INPUT)
   return trmstat;

   /* Fine, everything O.K. */

   return SS$_NORMAL;
  }
  /* =0C */

  case CHKLGI$_DIALUP:
  case CHKLGI$_LOCAL:
  {
   /* We accept a 'usrnam' and/or 'lgidev' argument here. If 'usrnam'
      is specified, 'lgidev' is not further processed (used for auditing
      only). Otherwise, 'lgidev' must be specified and is used by ALF
      to obtain a username. */

   if ((usrnam =3D=3D NULL && lgidev =3D=3D NULL) || reminf !=3D NULL) re=
turn SS$_CONFQUAL;

   /* If a username was given as input, return it. */

   if (usrnam !=3D NULL) status =3D getuai(usrnam,lgi);

   else
   {
    /* No username was given, so ALF processing must be done. If an
       access port name exists, we use it as key (this is required
       for logins via LAT). Otherwise, we use the physical device
       name for logins over serial line or modem. */

    if (lgi->T_ACCPORNAM[0])
    {
     if ((status =3D getalf(lgi->T_ACCPORNAM,retusr)) !=3D SS$_NORMAL) re=
turn status;
    }
    else
    {
     if ((status =3D getalf(lgi->T_PHYDEVNAM,retusr)) !=3D SS$_NORMAL) re=
turn status;
    }
    /* Mark that this login is an auto-login (required for later
       checks). */

    lgi->L_IFLAGS |=3D CHKLGI$M_AUTO_LOGIN;

    /* Get information about the user given by ALF. */

    status =3D getuai(retusr,lgi);
   }
   /* If an error occured, return it. */

   if (status !=3D SS$_NORMAL) return status;

   /* Otherwise, if gettrm's status was LGI$_INVINPUT, return it. */

   else if (trmstat =3D=3D LGI$_INVINPUT) return trmstat;

   return status;
  }
  /* =0C */

  case CHKLGI$_REMOTE:
  {
   /* For this login source, we accept all arguments. If 'lgidev'
      is specified, we use it for ALF processing. Otherwise, we
      use 'reminf'. At least one of the three args _must_ be
      supplied, however. */

   if (usrnam =3D=3D NULL && lgidev =3D=3D NULL && reminf =3D=3D NULL) re=
turn SS$_CONFQUAL;

   /* If a 'usrnam' argument was given, use it. */

   if (usrnam !=3D NULL) status =3D getuai(usrnam,lgi);

   else
   {
    /* Mark this login as auto-login. */

    lgi->L_IFLAGS |=3D CHKLGI$M_AUTO_LOGIN;

    /* Use ALF to obtain a username. If a 'lgidev' arg was supplied,
       use the obtained access port or physical terminal string (access
       port info is used if available, otherwise, the physical terminal
       name is used). */

    if (lgidev !=3D NULL)
    {
     if (lgi->T_ACCPORNAM[0])
     {
      if ((status =3D getalf(lgi->T_ACCPORNAM,retusr)) !=3D SS$_NORMAL) r=
eturn status;
     }
     else
     {
      if ((status =3D getalf(lgi->T_PHYDEVNAM,retusr)) !=3D SS$_NORMAL) r=
eturn status;
     }
    }
    else
    {
     /* Otherwise, pass the given 'reminf' argument to ALF. */

     if ((status =3D getalf(reminf,retusr)) !=3D SS$_NORMAL) return statu=
s;
    }
    /* Get information about this user. */

    status =3D getuai(retusr,lgi);
   }
   /* If an error occured, return it. */

   if (status !=3D SS$_NORMAL) return status;

   /* Otherwise, if gettrm's status was LGI$_INVINPUT, return it. */

   else if (trmstat =3D=3D LGI$_INVINPUT) return trmstat;

   return status;
  }
  /* =0C */

  case CHKLGI$_NETWORK:
  {
   /* We accept a 'usrnam' and/or 'reminf' argument here. If 'usrnam'
      is specified without 'reminf', it is used. Otherwise, a proxy is
      searched with the arguments given in 'reminf' and 'usrnam'. */

   if ((usrnam =3D=3D NULL && reminf =3D=3D NULL) || lgidev !=3D NULL) re=
turn SS$_CONFQUAL;

   /* Change the default username string to indicate network login. */

   strcpy(lgi->T_USRNAM,"<net>");

   /* If a 'usrnam' argument was given without 'reminf', use it directly.=
 */

   if (usrnam !=3D NULL && reminf =3D=3D NULL) return getuai(usrnam,lgi);

   /* Otherwise, check the proxy database for an existing proxy. */

   if ((status =3D getprx(reminf,usrnam,retusr)) =3D=3D SS$_NORMAL)

   return getuai(retusr,lgi);

   else return status;
  }
  /* All possible login sources are processed at this point. If we come
     here, the user specified an invalid source. Tell him. */

  default: return SS$_BADPARAM;
 }
}

/***=0C***/

/*** gettrm() ***/
/*** -------- ***/

/* This routine is used to obtain information about a given terminal
   and to ensure that it is a valid terminal. */

static int gettrm(char* lgidev, int lgisrc, char* phydevnam, char* accpor=
nam)
{
 /* Parameters:	trmnam...the name of the device which information should
		be obtained for

		lgisrc...the login source

		phydevnam...the physical or full device name

		accpornam...the access port name (if any)


   Return status: SS$_NORMAL...validation was OK

		  LGI$_INVINPUT...the given input device isn't a terminal

		  LGI$_NOTMODEM...remote modem not wired correctly

		  Any other return status from SYS$GETDVI.

******/

 char
 fulnam[64],			/* Full device name */
 phynam[64];			/* Physical device name */


 short
 fullen,			/* Length of full device name */
 phylen,			/* Length of physical device name */
 acclen,			/* Length of access port name */
 iosb[4];			/* I/O status block for SYS$GETDVI */


 int
 devcls,			/* device class */
 devtt,				/* terminal characteristics */
 status;			/* return status */

 $DESCRIPTOR(trmdsc,lgidev);	/* VMS descriptor for terminal name */

 struct itmlst itm[6] =3D		/* item list for SYS$GETDVI */
 {
  4, DVI$_DEVCLASS,    &devcls,0,
  4, DVI$_DEVDEPEND,   &devtt,0,=20
 63, DVI$_FULLDEVNAM,   fulnam, &fullen,
 63, DVI$_TT_PHYDEVNAM, phynam, &phylen,
 63, DVI$_TT_ACCPORNAM,accpornam, &acclen,
  0, 0
 };
 /* Setup the descriptor. */

 trmdsc.dsc$w_length =3D strlen(lgidev);

 /* Call SYS$GETDVIW to obtain this information: device class, physical
    terminal name and access port name (if any). */

 if ((status =3D sys$getdviw(0,0,&trmdsc,itm,iosb,0,0,0)) !=3D SS$_NORMAL=
)
    return status;

 /* Check the I/O status block. */

 if (iosb[0] !=3D SS$_NORMAL) return iosb[0];

 /* Mark the end of the various device name strings. */

 accpornam[acclen] =3D '\0';

 fulnam[fullen] =3D '\0';

 phynam[phylen] =3D '\0';

 /* If we got a physical device name, return it. Otherwise, return
    the full device name. */

 if (phylen) strcpy(phydevnam,phynam);

 else strcpy(phydevnam,fulnam);

 /* Check the device class. It must be either DC$_TERM (terminal) or
    DC$_WORKSTATION (DECwindows workstation device. */

 if (devcls !=3D DC$_TERM && devcls !=3D DC$_WORKSTATION) return LGI$_INV=
INPUT;

 /* If this is a terminal and was set to /MODEM, the TT_REMOTE
    characteristic must be set as well, otherwise return LGI$_NOTMODEM. *=
/

 if (devcls =3D=3D DC$_TERM)
 {
  if (devtt & TT$M_MODEM)
  {
   if (!(devtt & TT$M_REMOTE)) return LGI$_NOTMODEM;
  }
 }
 /* OK, thats all. Physical device name and access port name were already=
  =20
    placed in their approbiate buffers. Return to getusr(). */

 return SS$_NORMAL;
}

/***=0C***/

/*** getalf() ***/
/*** -------- ***/

/* This routine is used to emulate ALF processing. If the ALF database
   exists, it uses the given input string as key into the database. */

static int getalf(char* keystr, char* retusr)
{
 /* Parameters:	keystr...the key which we should look for

		retusr...the username which machtes the given key

   Return status: SS$_NORMAL: we've found a username.

		  LGI$_NOTVALID: user authorization failure

		  Any other return status from SYS$OPEN, SYS$CONNECT,
		  SYS$GET and SYS$CLOSE. Note that the return states
		  RMS$_FNF (file not found) and RMS$_RNF (record not
		  found) are converted to LGI$_NOTVALID.

******/

 char
 filnam[] =3D "SYSALF",		/* File name (or logical pointing to file */
 defnam[] =3D "SYS$SYSTEM:.DAT",	/* Default file name */
 record[ALF$C_LENGTH];		/* Buffer receiving record */

 int status;			/* Primary return status */

 struct FAB alf_fab;		/* RMS FAB (file access block) */
 struct RAB alf_rab;		/* RMS RAB (record access block) */

 /* First ensure that ALF is not processed from the system's console devi=
ce. */

 if (!(strcmp(keystr,"_OPA0:"))) return LGI$_NOTVALID;

 /* Now, initialize FAB. */

 alf_fab =3D cc$rms_fab;
 alf_fab.fab$b_acmodes =3D PSL$C_EXEC;	/* SYSALF trans in exec/krnl mode =
only*/
 alf_fab.fab$l_dna =3D defnam;		/* Default name */
 alf_fab.fab$b_dns =3D strlen(defnam);	/* Default name size */
 alf_fab.fab$b_fac =3D FAB$M_GET;		/* We want to read only */
 alf_fab.fab$l_fna =3D filnam;		/* File name */
 alf_fab.fab$b_fns =3D strlen(filnam);	/* File name size */
 alf_fab.fab$b_org =3D FAB$C_IDX;		/* Indexed file */
 alf_fab.fab$b_shr =3D FAB$M_GET|FAB$M_UPI|FAB$M_PUT|FAB$M_UPD; /* Sharin=
g opts */

 /* Open the ALF database. */

 status =3D sys$open(&alf_fab,0,0);

 /* If an error occured, lets check for RMS$_FNF (file not found). If so,
    there is no ALF database and we will return LGI$_NOTVALID instead. */

 if (status !=3D RMS$_NORMAL)
 {
  if (status =3D=3D RMS$_FNF) status =3D LGI$_NOTVALID;

  return status;
 }
 /* There is an ALF database to process. Initialize the RAB. */

 alf_rab =3D cc$rms_rab;
 alf_rab.rab$l_fab =3D &alf_fab;		/* Addr of corresponding FAB */
 alf_rab.rab$b_rac =3D RAB$C_KEY;		/* Keyed access */
 alf_rab.rab$b_ksz =3D strlen(keystr);	/* Size of key string */
 alf_rab.rab$l_kbf =3D keystr;		/* Address of key string */
 alf_rab.rab$b_krf =3D 0;			/* Reference by key #0 */
 alf_rab.rab$w_usz =3D ALF$C_LENGTH;	/* Length of user buffer */
 alf_rab.rab$l_ubf =3D record;		/* Address of user buffer */

 /* Connect the RAB to the FAB */

 status =3D sys$connect(&alf_rab,0,0);

 /* If error, close the FAB and return */

 if (status !=3D RMS$_NORMAL)
 {
  sys$close(&alf_fab);

  return status; =20
 }
 /* Get the record and immediately close the ALF database */

 status =3D sys$get(&alf_rab,0,0);

 sys$close(&alf_fab);

 /* If the return code is RMS$_RNF (record not found), convert it
    to LGI$_NOTVALID; */

 if (status !=3D RMS$_NORMAL)
 {
  if (status =3D=3D RMS$_RNF) status =3D LGI$_NOTVALID;

  return status;
 }
 /* A valid record was found. Return it to the user. Since the username
    is returned as blank-filled string, truncate the string first to 13
    chars (the maximum username length + 1) and then skip the characters
    starting with the first blank. */

 strncpy (retusr,&record[ALF$T_USERNAME],14);

 retusr[strcspn(retusr," ")] =3D '\0';

 /* All fine, return now. */

 return SS$_NORMAL;
}

/***=0C***/

/*** getprx() ***/
/*** -------- ***/

/* This routine is used to perform proxy processing. This is done simply
   by using the SYS$VERIFY_PROXY system service. */

static int getprx(char* reminf,char* usrnam,char* retusr)
{
 /* Parameters:	reminf...remote information in the format NODE::USER.

	        usrnam...if a proxy contains more targets, use this target.
			 This argument is optional

		retusr...the obtained target

   Return status: SS$_NORMAL: we've found a username.

		  LGI$_NOTVALID: no matching proxy was found or no username
				 was given and the matching proxy has no
			         DEFAULT entry.

		  LGI$_NOSUCHUSER: a matching proxy was found but without
				 the entry given in 'usrnam'.

		  Any other return status from SYS$VERIFY_PROXY. Note that
		  the return states SECSRV$_NOSUCHPROXY (no matching proxy
		  found) and SECSRV$_NOSUCHUSER (no valid user for requested
		  proxy found) are converted to LGI$_NOTVALID and
		  LGI$_NOSUCHUSER, respectively.

******/

 char
 retusrbuf[40],		/* Buffer receiving the target username */
 *ptr;			/* Auxiliary pointer */

 short
 retlen;		/* Word receiving the target user length */

 int
 status;		/* return status */

 $DESCRIPTOR(remnoddsc,retusrbuf);
 $DESCRIPTOR(remusrdsc,retusrbuf);
 $DESCRIPTOR(usrnamdsc,usrnam);
 $DESCRIPTOR(retusrdsc,retusrbuf);

 /* Ensure that VMS V6 (V6.1 VAX or V6.2 Alpha) is available. Otherwise,
    there is no documented way to perform proxy processing, so simply
    return LGI$_NOTVALID. */

#ifndef V6_OK
 return LGI$_NOTVALID;
#else

 /* Now, create two descriptors. Split the 'reminf' string at the
    current position, advance the pointer (which currently points to
    the first ':') to the start of the USER part of 'reminf' and set
    up the descriptors. */

 ptr =3D strstr(reminf,"::");

 *ptr =3D '\0';

 ptr +=3D 2;

 remnoddsc.dsc$w_length =3D strlen(reminf);
 remnoddsc.dsc$a_pointer =3D reminf;

 remusrdsc.dsc$w_length =3D strlen(ptr);
 remusrdsc.dsc$a_pointer =3D ptr;

 /* Omit the 'usrnam' argument, if it wasn't given. */

 if (usrnam !=3D NULL)
 {
  usrnamdsc.dsc$w_length =3D strlen(usrnam);

  status =3D sys$verify_proxy(&remnoddsc,&remusrdsc,&usrnamdsc,&retusrdsc=
,
	   &retlen,0);
 }
 else status =3D sys$verify_proxy(&remnoddsc,&remusrdsc,0,&retusrdsc,&ret=
len,0);

 /* In case of success, return the obtained name. */

 if (status =3D=3D SS$_NORMAL)
 {
  retusrbuf[retlen] =3D '\0';

  strcpy(retusr,retusrbuf);

  return SS$_NORMAL;
 }
 /* Otherwise, convert specific errors to LGI$_NOTVALID. */

 switch(status)
 {
  case SECSRV$_NOSUCHPROXY:
  case SECSRV$_SERVERNOTACTIVE: return LGI$_NOTVALID;

  case SECSRV$_NOSUCHUSER: return LGI$_NOSUCHUSER;

  default: return status;
 }
#endif	/* V6_OK */
}

/***=0C***/

/*** getuai() ***/
/*** -------- ***/

/* This routine obtains all information from the UAF database for further
   processing. If the given user doesn't exist, it returns LGI$_NOSUCHUSE=
R.

   If SYS$GETUAI returns RMS$_FNF and the system parameter UAFALTERNATE i=
s
   set to 1 and the login occurs on the console with username SYSTEM, we
   will allow the login and substitute standard values. */

static int getuai(char* usrnam,struct LGIBUF* recbuf)
{
 /* Parameters:	usrnam...user name which we should obtain information for

		recbuf...a pointer to a LGIBUF buffer. This buffer receives
			 all information and is used for all checks later

   Return status: SS$_NORMAL: we've found a username.

		  LGI$_NOSUCHUSER: user didn't exist in the UAF.

		  LGI$_FILEACC: error accessing UAF.

		  Any other return codes from SYS$GETUAI. Note that the
		  code RMS$_RNF (record not found) is converted to
		  LGI$_NOSUCHUSER and RMS$_FNF (file not found) is
		  converted to LGI$_FILEACC. */

/******/

 char
 cli[32],				/* Buffer to receive CLI name */
 clitab[32];				/* Buffer to receive CLITABLES */

 int
 status,				/* SYS$GETUAI return status */
 temp;					/* Temporary storage */

 $DESCRIPTOR(usrnamdsc,usrnam);		/* Descriptor for username */

 struct itmlst itm[30] =3D		/* item list for SYS$GETUAI */
 {
  32,UAI$_ACCOUNT,recbuf->T_ACCNAM,0,
   4,UAI$_UIC,&recbuf->L_UIC,0,

   3,UAI$_NETWORK_ACCESS_P,&recbuf->L_ACCESS[0],0,
   3,UAI$_NETWORK_ACCESS_S,&recbuf->L_ACCESS[1],0,
   3,UAI$_BATCH_ACCESS_P,&recbuf->L_ACCESS[2],0,
   3,UAI$_BATCH_ACCESS_S,&recbuf->L_ACCESS[3],0,
   3,UAI$_LOCAL_ACCESS_P,&recbuf->L_ACCESS[4],0,
   3,UAI$_LOCAL_ACCESS_S,&recbuf->L_ACCESS[5],0,
   3,UAI$_DIALUP_ACCESS_P,&recbuf->L_ACCESS[6],0,
   3,UAI$_DIALUP_ACCESS_S,&recbuf->L_ACCESS[7],0,
   3,UAI$_REMOTE_ACCESS_P,&recbuf->L_ACCESS[8],0,
   3,UAI$_REMOTE_ACCESS_S,&recbuf->L_ACCESS[9],0,
   4,UAI$_PRIMEDAYS,&recbuf->L_PRIMDAYS,0,

   1,UAI$_ENCRYPT,&recbuf->B_PWDENC[0],0,
   1,UAI$_ENCRYPT2,&recbuf->B_PWDENC[1],0,
   8,UAI$_PWD,recbuf->Q_PWD[0],0,
   8,UAI$_PWD2,recbuf->Q_PWD[1],0,
   8,UAI$_PWD_DATE,recbuf->Q_PWDDAT[0],0,
   8,UAI$_PWD2_DATE,recbuf->Q_PWDDAT[1],0,
   2,UAI$_SALT,&recbuf->W_PWDSALT,0,
   8,UAI$_PWD_LIFETIME,recbuf->Q_PWDTIM,0,
   8,UAI$_EXPIRATION,recbuf->Q_EXPTIM,0,

   4,UAI$_FLAGS,&recbuf->L_FLAGS,0,
   8,UAI$_DEF_PRIV,recbuf->Q_DEFPRIV,0,

  32,UAI$_DEFCLI,cli,0,
  32,UAI$_CLITABLES,clitab,0,

   2,UAI$_MAXACCTJOBS,&recbuf->W_MAXACCJOBS,0,
   2,UAI$_MAXJOBS,&recbuf->W_MAXJOBS,0,
   2,UAI$_LOGFAILS,&recbuf->W_LOGFAILS,0,

   0,0};

 /* Setup descriptor. */

 usrnamdsc.dsc$w_length =3D strlen(usrnam);=20

 /* Let's call SYS$GETUAI now. */

 status =3D sys$getuai(0,0,&usrnamdsc,itm,0,0,0);

 if (status =3D=3D SS$_NORMAL)
 {
  /* Overwrite the default name string with the valid username. */

  strcpy(recbuf->T_USRNAM,usrnam);

  /* Copy account name. It is returned as a fixed-length, blank-
     filled string. */

  recbuf->T_ACCNAM[strcspn(recbuf->T_ACCNAM," ")] =3D '\0';

  /* Copy CLI and CLITABLES. This information is returned as ASCIC
     string (first byte contains string length). */

  strncpy(recbuf->T_CLI,&cli[1],cli[0]);

  recbuf->T_CLI[cli[0]] =3D '\0';

  strncpy(recbuf->T_CLITAB,&clitab[1],clitab[0]);

  recbuf->T_CLITAB[clitab[0]] =3D '\0';

 /* All information is now in the LGIBUF data structure, so we can exit. =
*/

  return SS$_NORMAL;
 }
 /* If status is RMS$_FNF (file not found), we must check for a login
    attempt with alternate UAF:

    o - Login must occur on the console
    o - Given username must be "SYSTEM"
    o - System parameter UAFALTERNATE must be set to 1.

    In this case, substitute default values and let the user login. Other=
wise,
    return LGI$_FILEACC (error accessing authorization file). */

 if (status =3D=3D RMS$_FNF)=20
 {
  if (!conlgi(recbuf,usrnam)) return LGI$_FILEACC; /* No console login? E=
xit.*/

  /* Check whether UAFALTERNATE is set to 1. */

  if ((status =3D lib$getsyi(&SYI$_UAFALTERNATE,&temp)) !=3D SS$_NORMAL)
  return status;

  if (!temp) return LGI$_FILEACC;		/* UAFALTERNATE =3D 0? Abort. */

  /* A login occured on the console when UAFALTERNATE was 1. This is
     used on emergency when the system manager has forgotten its
     password. Grant this login and substitute defaults. */

  strcpy(recbuf->T_USRNAM,"SYSTEM");		/* Set username */

  strcpy(recbuf->T_ACCNAM,recbuf->T_USRNAM);	/* and account name */

  strcpy(recbuf->T_CLI,"DCL");			/* and CLI name */

  strcpy(recbuf->T_CLITAB,"DCLTABLES");		/* and CLI tables name */

  recbuf->L_UIC =3D 0x00010004;			/* UIC =3D [1,4] */

  recbuf->Q_DEFPRIV[0] =3D recbuf->Q_DEFPRIV[1] =3D -1; /* All privs are =
set */

  /* Mark this login as "alternate"; */

  recbuf->L_IFLAGS |=3D CHKLGI$M_ALTERNATE;

  /* No need to set other fields since they were initialized with 0 in
     the main routine which is sufficient. */

  return SS$_NORMAL;
 }
 /* Store the non-existent username in its own field (we'll
    require this later for auditing. */

 strcpy(recbuf->T_BADNAM,usrnam);

 /* If status is RMS$_RNF (record not found), convert it
    to LGI$_NOSUCHUSER, else return it unchanged. */

 return status =3D=3D RMS$_RNF ? LGI$_NOSUCHUSER : status;
} =20

=0C---------------------->>> #14: INTRUS.C <<<----------------------

#ifdef VAXC
#module INTRUS "BOL-V1.0/OCT-95"
#else
#pragma module INTRUS "BOL-V1.0/OCT-95"
#endif

/* This routine performs intrusion-related operations.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at) */

#ifdef __DECC		/* For VAXC, the following module doesn't exist: */
#include ciadef		/* CIA$M_xxx flag bits */
#endif
#include descrip	/* Definitions for descriptors */
#include stdio		/* Standard I/O definitions */
#include string		/* strxxx() function definitions */
#include starlet	/* SYS$xxx() system service definitions */
#include ssdef		/* SS$_xxx system status codes */

#include "chklgidef.h"  /* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"  /* LGIBUF structure field definitions */
#include "lgimsgdef.h"  /* LGI$_xxx login status codes */
#include "compdepnd.h"	/* Compiler dependencies (CIA$xxx symbols for VAXC=
 */

/*** =0C ***/

/*** INTRUS() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 lgistat:   Status of login attempt, by value

 lgi:       Login buffer containing additional information. By reference


 Return codes:

	LGI$_EVADE:	Breakin evasion in progress

	The given login status

	Any error code returned by SYS$SCAN_INTRUSION

=0C */

typedef struct dsc$descriptor_s dsc;    /* Abbreviation for descriptor st=
ruct.*/

int intrus(int lgistat,struct LGIBUF* lgi)
{
 /* Intrusion database scanning is done by the new SYS$SCAN_INTRUSION
    system service. This service exists on OpenVMS VAX V6.1 and
    OpenVMS Alpha V6.2 and higher only. If we are running an older
    version, simply return the given status. */

#ifndef V6_OK
 return lgistat;
#else

 /* Otherwise, use the new system service. */

 char
 *ptr;					/* Auxiliary pointer */

 int
 tmp =3D 0, 				/* Auxiliary variable */
 flags,					/* System service flags */
 status;				/* Return status */

 $DESCRIPTOR (usr, ptr);
 $DESCRIPTOR (trm, ptr);
 $DESCRIPTOR (srcnod, ptr);
 $DESCRIPTOR (srcusr, ptr);

 /* Intrusion processing only occurs for the following login failures:

    LGI$_NOTVALID	User authorization failure
    LGI$_NOSUCHUSER	No such user
    LGI$_INVPWD		Invalid password
    LGI$_DISUSER	Account is disabled

    In all other cases, the login is rejected, but no intrusion record
    is created. */

 switch (lgistat)
 {
  case LGI$_NOTVALID:
  case LGI$_NOSUCHUSER:
  case LGI$_DISUSER:		/* For these failures, intrusion processing */
  case LGI$_INVPWD: break;	/* must be done. */

  default: return lgistat;	/* Otherwise, simply return. */
 }
 /* Set control flags initially. Don't audit, we perform our own auditing=
. */

 flags =3D CIA$M_NOAUDIT;

 /* Build the descriptor for the username. */

 usr.dsc$w_length =3D strlen(lgi->T_USRNAM);
 usr.dsc$a_pointer =3D lgi->T_USRNAM;

 /* Pass different information to the system service, depending on the
    given arguments. Note: passwords are not supplied here; they are
    used by SYS$SCAN_INTRUSION for auditing only. Since we do our own
    auditing later, we can omit them here. */

 while (1)
 {
  /* If a remote info was specified, pass it. In this, we create an
     intrusion record of type "NETWORK". */

  if (lgi->T_REMINF[0])
  {
   ptr =3D strstr(lgi->T_REMINF,"::");

   srcnod.dsc$w_length =3D strlen(lgi->T_REMINF) - strlen(ptr);

   srcnod.dsc$a_pointer =3D lgi->T_REMINF;

   srcusr.dsc$w_length =3D strlen(ptr) - 2;

   srcusr.dsc$a_pointer =3D ptr + 2;

   status =3D sys$scan_intrusion (lgistat,	/* Login status */
				&usr,		/* Username */
				lgi->L_LGISRC,	/* Login type */
				0,		/* No source terminal */
				&srcnod,	/* Source node */
				&srcusr, 	/* Source user */
				0,		/* No source address */
				0,0,0,		/* No pwd and parent info */
				flags);		/* And our flags */
   break;
  }
  /* If an access port name exists in the REMNOD::REMUSR format,
     we must create a NETWORK record as well. This occurs for
     RTAn: devices used with remote interactive logins. */

  if (lgi->T_ACCPORNAM[0])
  {
   if ((ptr =3D strstr(lgi->T_ACCPORNAM,"::")) !=3D NULL)
   {
    srcnod.dsc$w_length =3D strlen(lgi->T_ACCPORNAM) - strlen(ptr);

    srcnod.dsc$a_pointer =3D lgi->T_ACCPORNAM;

    srcusr.dsc$w_length =3D strlen(ptr) - 2;

    srcusr.dsc$a_pointer =3D ptr + 2;

    status =3D sys$scan_intrusion(lgistat,	/* Login status */
				&usr,		/* Username */
				lgi->L_LGISRC,	/* Login type */
				0,		/* No source terminal */
				&srcnod,	/* Source node */
				&srcusr, 	/* Source user */
				0,		/* No source address */
				0,0,0,		/* No pwd and parent info */
				flags);		/* And our flags */
    break;
   }
  }
  /* Pass the terminal name to SYS$SCAN_INTRUSION, it will obtain
     the access port name, if one is available. Depending on the
     username, either build a TERM_USER record (username was
     valid) or TERMINAL record (username wasn't valid). Bypass
     this for detached logins with a mailbox as login device. */

  if (lgi->T_PHYDEVNAM[0] && lgi->L_LGISRC !=3D CHKLGI$_DETACHED)
  {
   trm.dsc$w_length =3D strlen(lgi->T_PHYDEVNAM);

   trm.dsc$a_pointer =3D lgi->T_PHYDEVNAM;

   /* If the user exists (the username string doesn't start
      with '<'), mark it as real user to create a TERM_USER
      record. */

   if (lgi->T_USRNAM[0] !=3D '<') flags |=3D CIA$M_REAL_USERNAME;

   status =3D sys$scan_intrusion(lgistat,		/* Login status */
		  	       &usr, 		/* Username */
			       lgi->L_LGISRC,	/* Login type */
		               &trm,		/* Source terminal, if any */
			       0,		/* No source node */
			       0, 		/* No source user */
			       0,		/* No source address */
			       0,0,0,		/* No pwd and parent info */
			       flags);		/* And our flags */
   break;
  }
  /* Otherwise, we have no more info, so we can supply the username only.=
 */

  flags |=3D CIA$M_REAL_USERNAME;

  status =3D sys$scan_intrusion(lgistat,		/* Login status */
			      &usr,		/* Username */
			      lgi->L_LGISRC,	/* Login type */
			      0,		/* No source terminal */
			      0,		/* No source node */
			      0, 		/* No source user */
			      0,		/* No source address */
			      0,0,0,		/* No pwd and parent info */
			      flags);		/* And our flags */
  break;
 }
 /* Convert the return status to a login-specific code. If the status
    is informational, return the status given as input. If it is SECSRV$_
    INTRUDER (intrusion was found), convert it to LGI$_EVADE (breakin-
    evasion is in effect); if it is SECSRV$_SERVERNOTACTIVE (security
    server not running), convert it to LGI$_NOTVALID (user authorization
    failure). Otherwise, return it as is. */

 switch (status)
 {
  case SS$_NORMAL:
  case SECSRV$_SUSPECT:
  case SECSRV$_NOSCANNEDINTRUDER: return lgistat;

  case SECSRV$_SERVERNOTACTIVE: return LGI$_NOTVALID;

  case SECSRV$_INTRUDER: return LGI$_EVADE;

  default: return status;
 }
 /* That's all here. */

#endif	/* V6_OK */
}

=0C---------------------->>> #15: LOGIN.C <<<----------------------

#ifdef VAXC
#module LOGIN "BOL-V1.0/OCT-95"
#else
#pragma module LOGIN "BOL-V1.0/OCT-95"
#endif

/* This is a simple test program to see and check the
   behaviour of the chklgi() routine.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at).

   Syntax for activation:

   $ MCR SYS$DISK:[]LOGIN lgityp usr srctrm reminf pwd1 pwd2 day flg

   All parameters except 'lgityp' are optional.

   For a description of the parameters, see $$$CHKLGI.DOC. */

#include descrip			/* Definitions for descriptors */
#include string				/* strxxx() function definitions */
#include stdlib				/* atoi() function */
#include stdio				/* printf() function */
#include ssdef				/* SS$_xxx system status codes */

#include "chklgidef.h"			/* CHKLGI$_xxx definitions */
#include "lgimsgdef.h"			/* LGI$_xxx return codes */

int chklgi();

int main(int argc,char **argv)
{
 char
 usrnam[14],				/* Username */
 lgidev[64],				/* Login device (terminal) */
 reminf[256],				/* Remote Information */
 pwd1[32],				/* Primary Password */
 pwd2[32],				/* Secondary Password */
 cli[] =3D "DCL",				/* CLI Name */
 tab[] =3D "DCLTABLES";			/* CLI Table Name */

 int
 status,				/* Return status */
 lgityp,				/* Login source */
 lgiday,				/* Login day */
 lgiflg =3D 0;				/* Login flags */

 $DESCRIPTOR(usrnamdsc,usrnam);		/* Descriptor for username */
 $DESCRIPTOR(lgidevdsc,lgidev);		/* Descriptor for login device */
 $DESCRIPTOR(reminfdsc,reminf);		/* Descriptor for remote info */
 $DESCRIPTOR(pwd1dsc,pwd1);		/* Descriptor for prim. password */
 $DESCRIPTOR(pwd2dsc,pwd2);		/* Descriptor for sec. password */

 struct					/* Item list for input items. */
 {					/* This list is code fix in the */
  short size;				/* program, you can't supply */
  short code;				/* the value on the command line. */
  void* info;
  void* unused;
 } itmlst[5] =3D
 {
  3,CHKLGI$_CLI,cli,0,			/* /CLI=3D<cli> was specified */
  9,CHKLGI$_TABLES,tab,0,		/* /CLITABLES=3D<table> was specified */
  0,CHKLGI$_COMMAND,0,0,		/* /[NO]COMMAND was specified */
  0,CHKLGI$_CONNECT,0,0,		/* /[NO]CONNECT was specified */
  0,0
 };

 /* If insufficient argument were specified or help was requested,
    print help text. */

 if (argc < 3 || (argc >=3D 3 && argv[1][0] =3D=3D '?'))
 {
  printf ("Demo tool to check the behaviour of CHKLGI\n\n");
  printf ("Syntax: LOGIN typ usr dev rem pw1 pw2 day flg\n\n");
  printf ("  typ...login type (source)\n");
  printf ("  usr...valid username\n");
  printf ("  dev...login device (terminal name)\n");
  printf ("  rem...remote info (SERVER/PORT or NODE::USER)\n");
  printf ("  pw1...primary password\n");
  printf ("  pw2...secondary password\n");
  printf ("  day...login day\n");
  printf ("  flg...control flags\n");

  return SS$_NORMAL;
 }
 /* Get the login source. */

 lgityp =3D atoi(argv[1]);

 /* Now get rest of arguments, if supplied. */

 if (argc > 2)
 {
  strcpy (usrnam,argv[2]);

  usrnamdsc.dsc$w_length =3D strlen(usrnam);
 }
 if (argc > 3)
 {
  strcpy (lgidev,argv[3]);

  lgidevdsc.dsc$w_length =3D strlen(lgidev);
 }
 if (argc > 4)
 {
  strcpy (reminf,argv[4]);

  reminfdsc.dsc$w_length =3D strlen(reminf);
 }
 if (argc > 5)
 {
  strcpy (pwd1,argv[5]);

  pwd1dsc.dsc$w_length =3D strlen(pwd1);
 }
 if (argc > 6)
 {
  if (strlen(argv[6]) > 31) return SS$_BADPARAM;

  strcpy (pwd2,argv[6]);

  pwd2dsc.dsc$w_length =3D strlen(pwd2);
 }
 if (argc > 7) lgiday =3D atoi(argv[7]);

 if (argc > 8) lgiflg =3D atoi(argv[8]);

 /* Force intrusion check and UAF update as well. */

 lgiflg |=3D CHKLGI$M_INTRUSION|CHKLGI$M_UPDATE_UAF;

 /* Call chklgi(). */

 status =3D chklgi(
	argc > 2 ? &usrnamdsc : 0,	/* Username */
	argc > 3 ? &lgidevdsc : 0,	/* Login device */
	argc > 4 ? &reminfdsc : 0,	/* Remote information */
	argc > 5 ? &pwd1dsc : 0,	/* Primary password */
	argc > 6 ? &pwd2dsc : 0,	/* Secondary password */
	&lgityp,			/* Login source */
	0,				/* Login time (use current time) */
	argc > 7 ? &lgiday : 0,		/* Login day */
	&lgiflg,			/* Login flags */
	itmlst,				/* Input item (qualifier) list */
	0);				/* No output item list */

 /* If the status is unsuccessfull, return it. Otherwise, if it contains
    a login-specific informational code, print a message. */

 if (!(status & 1)) return status;

 if (status =3D=3D LGI$_LOGOPRCON) printf("Logins are allowed from OPA0:"=
);

 if (status =3D=3D LGI$_LICNOTREQ) printf("License check not required for=
 this process");

 return status;
}

=0C---------------------->>> #16: UPDUAF.C <<<----------------------

#ifdef VAXC
#module UPDUAF "BOL-V1.0/OCT-95"
#else
#pragma module UPDUAF "BOL-V1.0/OCT-95"
#endif

/* This routine updates login-related information in the user's UAF recor=
d.

   (P) 1995 by Ing. Ferry Bolh=E1r (bol@adv.magwien.gv.at). */

#include descrip	/* Definitions for descriptors */
#include rmsdef		/* RMS$_xxx error codes */
#include ssdef		/* SS$_xxx system error codes */
#include stdio		/* Standard I/O definitions */
#include string		/* strxxx() function definitions */
#include starlet	/* SYS$xxx() system service definitions */
#include uaidef		/* UAI$_xxx item codes */

#include "chklgidef.h"  /* CHKLGI$_xxx login source constants */
#include "lgibufdef.h"  /* LGIBUF structure field definitions */
#include "lgimsgdef.h"  /* LGI$_xxx login status codes */

/*** =0C ***/

/*** UPDUAF() ***/
/*** =3D=3D=3D=3D=3D=3D=3D=3D ***/

/* Input arguments:

 lgistat:  Status of login attempt, by value

 lgi:      Login buffer containing additional information. By reference

 curtim:   Login time (binary). By reference


 Return codes:

        The given login status

        Any error code returned by SYS$SETUAI

=0C */

typedef struct dsc$descriptor_s dsc;    /* Abbreviation for descriptor st=
ruct.*/

int upduaf(int lgistat,struct LGIBUF* lgi,int *curtim)
{
 /* For pre-V6 systems, the items UAI$_LASTLOGIN_x and UAI$_LOGFAILS are
    read-only, we can't update them. So simply return the given login
    status in this case. */

#ifndef V6_OK
 return lgistat;
#else

 int
 flags,					/* UAF flags */
 status;				/* Return status */

 $DESCRIPTOR (usrdsc,lgi->T_USRNAM);

 struct itmlst log_ok[3] =3D		/* Item list for login success: */
 {
  8,UAI$_LASTLOGIN_I,curtim,0,		/* Update last login date and */
  2,UAI$_LOGFAILS,&lgi->W_LOGFAILS,0,	/* time and reset logfailures */
  0,0
 };

 struct itmlst log_fail[3] =3D
 {
  2,UAI$_LOGFAILS,&lgi->W_LOGFAILS,0,	/* Inc no. of logfailures */
  0,0
 };

 /* First of all, we need a valid (not pseudo) username. Pseudo-
    users always start with a '<' in their name strings. */

 if (lgi->T_USRNAM[0] =3D=3D '<') return lgistat;

 /* If this is an 'alternate' login (with UAFALTERNATE set to 1 and
    no alternate UAF exists) we can't update a record. Return. */

 if (lgi->L_IFLAGS & CHKLGI$M_ALTERNATE) return lgistat;

 /* Well, we can do something. Update length of username in descriptor. *=
/

 usrdsc.dsc$w_length =3D strlen(lgi->T_USRNAM);

 /* If the login status is successful, update last login date/time and
    clear # of logfailures. */

 if (lgistat & 1)
 {
  lgi->W_LOGFAILS =3D 0;

  /* If this is a non-interactive login, change the item code in
     the item list. */

  if (lgi->L_LGISRC < CHKLGI$_INTERACTIVE) log_ok[0].code =3D UAI$_LASTLO=
GIN_N;

  /* Write back the UAF record. */

  status =3D sys$setuai(0,0,&usrdsc,log_ok,0,0,0);
 }
 else
 {
  /* Otherwise, increment login failure count. */

  lgi->W_LOGFAILS++;

  /* Write back the UAF record. */

  status =3D sys$setuai(0,0,&usrdsc,log_fail,0,0,0);
 }
 /* Fine, that's all. If SYS$SETUAI failed, let the user know. */

 if (status !=3D SS$_NORMAL) return status;

 /* Else return login status. */

 else return lgistat;

#endif	/* V6_OK */
}

=0C---------------------->>> #17: CHKLGIDEF.H <<<----------------------

/*** CHKLGIDEF.H ***/
/*** ----------- ***/

#ifndef __CHKLGIDEF_LOADED
#define __CHKLGIDEF_LOADED 1

/* This module only contains definitions for the CHKLGI$_xxxx constants. =
*/

/* Definitions for CHKLGI 'lgisrc' argument. */

#define CHKLGI$_DETACHED	0
#define CHKLGI$_NETWORK		1
#define CHKLGI$_BATCH		2
#define CHKLGI$_LOCAL		3
#define CHKLGI$_INTERACTIVE	3
#define CHKLGI$_DIALUP		4
#define CHKLGI$_REMOTE		5
#define CHKLGI$_DECWINDOWS	6

/* Definitions for CHKGLI 'flags' argument */

#define CHKLGI$M_SKP_DISACC_CHK	1	/* Skip account disabled check */
#define CHKLGI$M_SKP_EXPACC_CHK	2	/* Skip account expired check */
#define CHKLGI$M_SKP_HOUR_CHK	4	/* Skip login time check */
#define CHKLGI$M_SKP_DAY_CHK	8	/* Skip login day check */
#define CHKLGI$M_SKP_SRC_CHK	16	/* Skip login source check */
#define CHKLGI$M_SKP_MAXUSR_CHK	32	/* Skip maximum processes/username */
#define CHKLGI$M_SKP_MAXACC_CHK	64	/* Skip maximum processes/accout */
#define CHKLGI$M_SKP_MAXINT_CHK 128	/* Skip maximum interactive users */
#define CHKLGI$M_SKP_EXPPWD_CHK	256	/* Skip password expired check */
#define CHKLGI$M_SKP_ALOGIN_CHK	512	/* Skip account auto-login only */
#define CHKLGI$M_SKP_DWICAP_CHK	1024	/* Skip DECwindows capt. account che=
ck*/
#define CHKLGI$M_SKP_LIC_CHK	2048	/* Skip licenses checks */
#define CHKLGI$M_SKP_LGIDIS_CHK	4096	/* Skip login disabled check */
#define CHKLGI$M_DO_CLI_CHK	8192	/* Perform CLI-related checks */

#define CHKLGI$M_NO_AUDIT	65536	/* Do not send audit information */
#define CHKLGI$M_UPDATE_UAF	131072	/* Update fields in UAF */
#define CHKLGI$M_INTRUSION	262144	/* Scan and update intrusion database *=
/
#define CHKLGI$M_AUTO_LOGIN	524288	/* Perform auto-login (internal) */
#define CHKLGI$M_ALTERNATE	1048576	/* Alternate UAF used (internal) */
#define CHKLGI$M_DISABL_UAF	2097152	/* Disabled entire UAF entry */

/* The same for bit number values */

#define CHKLGI$V_SKP_DISACC_CHK	0	/* Skip account disabled check */
#define CHKLGI$V_SKP_EXPACC_CHK	1	/* Skip account expired check */
#define CHKLGI$V_SKP_HOUR_CHK	2	/* Skip login time check */
#define CHKLGI$V_SKP_DAY_CHK	3	/* Skip login day check */
#define CHKLGI$V_SKP_SRC_CHK	4	/* Skip login source check */
#define CHKLGI$V_SKP_MAXUSR_CHK	5	/* Skip maximum processes/username */
#define CHKLGI$V_SKP_MAXACC_CHK	6	/* Skip maximum processes/accout */
#define CHKLGI$V_SKP_MAXINT_CHK 7	/* Skip maximun interactive users */
#define CHKLGI$V_SKP_EXPPWD_CHK	8	/* Skip password expired check */
#define CHKLGI$V_SKP_ALOGIN_CHK	9	/* Skip account auto-login check */
#define CHKLGI$V_SKP_DWICAP_CHK	10	/* Skip DECwindows capt. account check=
*/
#define CHKLGI$V_SKP_LIC_CHK	11	/* Skip licenses checks */
#define CHKLGI$V_SKP_LGIDIS_CHK	12	/* Skip login disabled check */
#define CHKLGI$V_DO_CLI_CHK	13	/* Perform CLI-related checks */

#define CHKLGI$V_NO_AUDIT	16	/* Do not send audit information */
#define CHKLGI$V_UPDATE_UAF	17	/* Update fields in UAF */
#define CHKLGI$V_INTRUSION	18	/* Scan and update intrusion database */
#define CHKLGI$V_AUTO_LOGIN	19	/* Perform auto-login (internal) */
#define CHKLGI$V_ALTERNATE	20	/* Alternate UAF used (internal) */

/* Definitions for CHKGLI item list */

#define CHKLGI$_CLI		1	/* /CLI=3D<name> was specified */
#define CHKLGI$_TABLES		2	/* /TABLES=3D<name> was specified */
#define CHKLGI$_COMMAND		3	/* /COMMAND=3D<name> or /NOCOMMAND */
#define CHKLGI$_CONNECT		4	/* /CONNECT was specified */
#define CHKLGI$_DISK		5	/* /DISK=3D<name> was specified */
#endif

=0C---------------------->>> #18: COMPDEPND.H <<<----------------------


/*** COMPDEPND.H ***/
/*** ----------- ***/

#ifndef __COMPDEPND_LOADED
#define __COMPDEPND_LOADED 1



/* Define error codes which may be undefined in STARLET. */

#ifndef SS$_NOAUDIT
#define SS$_NOAUDIT	0x292C		/* No AUDIT privilege */
#endif

#ifndef SS$_CONFQUAL
#define SS$_CONFQUAL	0x12E4		/* Conflicting arguments */
#endif

/* Platform- and compiler-depended definitions. */
/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */


/* Definitions for Alpha */
/* --------------------- */

#ifdef __ALPHA
extern EXE$GL_FLAGS;			/* Executive flags */
extern SYS$GL_IJOBCNT;			/* Interactive job count */
extern SYS$GW_IJOBLIM;			/* Interactive job limit */
extern VMS$GL_LICENSE_VERSION;		/* Binary VMS version */
extern VMS$GQ_LICENSE_DATE;		/* Binary VMS release date */
#define IJOBCNT SYS$GL_IJOBCNT

/* Definitions for VAX, DECC */
/* ------------------------- */

#else
#ifdef __DECC
extern EXE$GL_FLAGS;			/* Executive flags */
extern SYS$GW_IJOBCNT;			/* Interactive job count */
extern SYS$GW_IJOBLIM;			/* Interactive job limit */
extern VMS$GL_LICENSE_VERSION;		/* Binary VMS version */
extern VMS$GQ_LICENSE_DATE;		/* Binary VMS release date */


/* Definitions for VAX, VAXC */
/* ------------------------- */

#else
globalref EXE$GL_FLAGS;			/* Executive flags */
globalref SYS$GW_IJOBCNT;		/* Interactive job count */
globalref SYS$GW_IJOBLIM;		/* Interactive job limit */
globalref VMS$GL_LICENSE_VERSION;	/* Binary VMS version */
globalref VMS$GQ_LICENSE_DATE;		/* Binary VMS release date */

/* Define some constants and literals. They may be not defined in
   VAXCDEF.TLB since they were not present in previous VMS versions
   when the VAX C compiler was installed an VAXCDEF.TLB was built
   from starlet. */

#ifndef UAI$C_MAX_PWD_LENGTH
#define UAI$C_MAX_PWD_LENGTH 0x20	/* Maximum password length */
#endif

#ifndef NSA$_ALARM_NAME			/* NSA (audit-specific) definitions */
#define NSA$C_MSG_BREAKIN	3	/* Breakin attempt  */
#define NSA$C_MSG_LOGFAIL	5	/* Login failure    */
#define NSA$C_MSG_LOGIN		6	/* Successful login */
#define NSA$C_BATCH		1
#define NSA$C_DETACHED		2
#define NSA$C_DIALUP		3
#define NSA$C_LOCAL		4
#define NSA$C_NETWORK		5
#define NSA$C_REMOTE		6
#define NSA$M_FLUSH		0x0040	/* Flush event buffer */
#define NSA$M_NOEVTCHECK	0x2000	/* Don't check for events */
#define NSA$M_SUBJECT_OWNER	0x0800	/* Don't display UIC */
#define NSA$M_TERMINAL		0x1000	/* Don't display terminal name */
#define NSA$_ALARM_NAME		3	/* Alarm journal name */
#define NSA$_AUDIT_NAME		6	/* Audit journal name */
#define NSA$_PARENT_USERNAME	38	/* Parent username */
#define NSA$_PASSWORD		39	/* Breakin password */
#define NSA$_REMOTE_NODE_ID	43	/* Node ID of network source */
#define NSA$_REMOTE_NODENAME	44	/* Remote nodename */
#define NSA$_REMOTE_USERNAME	45	/* Remote username */
#define NSA$_SUBJECT_OWNER	47	/* Process owner (UIC) */
#define NSA$_FINAL_STATUS	48	/* Completion status */
#define NSA$_TERMINAL		49	/* Process terminal name */
#define NSA$_TIME_STAMP		50	/* When the event took place */
#define NSA$_USERNAME		56	/* Requestor username */
#define NSA$_EVENT_TYPE		89	/* Event message type */
#define NSA$_EVENT_SUBTYPE	90	/* Event message subtype */
#define NSA$_MESSAGE		149	/* Associated message code */
#define NSA$_SUPPRESS		190	/* Suppress supplied items */
#endif

#ifndef CIA$M_NOAUDIT			/* CIA (intrusion-specific) symbols */
#define CIA$M_NOAUDIT		0x0800	/* Don't audit */
#define CIA$M_REAL_USERNAME	0x1000	/* This is a real username */
#endif

#ifndef LMF$_PROD_VERSION		/* LMF (license management facility) */
#define LMF$_PROD_VERSION	3	/* Items and flags for the licensing */
#define LMF$_PROD_DATE		4	/* system services */
#define LMF$M_RETURN_FAILURES	1
#endif

#ifndef LICENSE$_EXCEEDED		/* License return code */
#define LICENSE$_EXCEEDED	0x0A948E1C
#endif

/* Reflect the change of the CAPTIVE flag and the new RESTRICTED flag
   in VMS V5.2 and higher. */

#ifdef UAI$M_CAPTIVE			/* Delete old definition. */
#undef UAI$M_CAPTIVE
#endif

#define UAI$M_RESTRICTED 0x0008		/* Define new RESTRICTED but */
#define UAI$M_CAPTIVE	0x10000		/* (Re)define CAPTIVE bit */
#endif

/* Definition for VAX (both compilers) */
/* ----------------------------------- */

#define IJOBCNT SYS$GW_IJOBCNT
#endif

#ifndef PCB$M_NOACNT
#define PCB$M_NOACNT	0x8000		/* No Accounting Bit */

int sys$lookup_license();		/* Function declaration */

#endif
#endif

=0C---------------------->>> #19: LGIBUFDEF.H <<<----------------------


/*** LGIBUFDEF.H ***/
/*** ----------- ***/

#ifndef __LGIBUFDEF_LOADED
#define __LGIBUFEDF_LOADED 1

/* This include file contains a description of the LGIBUF structure.
   This structure contains all information processed by CHKLGI. */

#ifdef __ALPHA
#pragma __nostandard
#pragma __member_alignment __save
#pragma __nomember_alignment
#endif

struct LGIBUF
{
 /* Lets start with information regarding auditing and
    intrusion processing. */

 int   L_LGISRC;	/* Login source (process type) */
 int   L_UIC;		/* User's UIC */
 char  T_USRNAM[14];	/* Name of user who requested login */
 char  T_BADNAM[14];	/* Invalid name specified by the user */
 char  T_PASSWD[34];	/* Password (or "<valid>" if correct) */
 char  T_REMINF[256];	/* Remote info, either 'NODE::USER' or 'SERVER/PORT=
' */
 char  T_PHYDEVNAM[64]; /* Physical terminal device name */
 char  T_ACCPORNAM[64]; /* Terminal access port name */

/* Here are all fields we require for login date/time validation. */

 int   L_ACCESS[10];	/* Access hours for primary/secondary days */
 int   L_PRIMDAYS;	/* Bit mask containing user's primary days */

/* Here are all fields we require for password validation. */

 int   Q_PWD[2][2];	/* Primary and secondary encrypted password */
 char  B_PWDENC[2];	/* Primary and secondary encryption mechanism */
 short W_PWDSALT;	/* Salt value */
 int   Q_PWDTIM[2];	/* Password life time */
 int   Q_EXPTIM[2];	/* Account expiration time */
 int   Q_PWDDAT[2][2];	/* Time of last password changes */

/* Job- or account-wide quota checks: */

 char  T_ACCNAM[32];	/* Target account name */
 short W_MAXACCJOBS;	/* Maximum jobs for the account */
 short W_MAXJOBS;	/* Maximum jobs for the user */

/* Miscellaneous fields */

 char  T_CLI[32];	/* Name of CLI used */
 char  T_CLITAB[32];	/* Name of CLITABLES used */
 int   L_FLAGS;		/* Flags in UAF record */
 int   L_IFLAGS;	/* Internal and user-supplied flags */
 short W_LOGFAILS;	/* Number of login failures */
 int   Q_DEFPRIV[2];	/* Default privileges */

/* Well, that's all. */

};

/* The following items aren't defined in the C version of STARLET. */

#define PRV$M_AUDIT	32
#define PRV$M_SECURITY	64

/* Structure definition for item-3 list */

struct itmlst
{
 short size;		/* Item size */
 short code;		/* Item code */
 void* info;		/* Item information */
 void* len;		/* Item length (or unused) */
};

#ifdef __ALPHA
#pragma __member_alignment __restore
#pragma __standard
#endif

#endif

=0C---------------------->>> #20: LGIMSGDEF.H <<<----------------------

/*** LGIMSGDEF.H ***/
/*** ----------- ***/

#ifndef __LGIMSGDEF_LOADED
#define __LGIMSGEDF_LOADED 1

/* This file contains definitions for the various LGI (login) message
   codes. We define only the codes we will required later. */

#define LGI$_FACILITY		0x00D30000

#define LGI$_LOGDISABL		0X00D38014  /* Logins are disabled */
#define LGI$_EXQUOTA		0X00D3801C  /* Login quota exceeded */
#define LGI$_CLIFAIL		0X00D38024  /* Error activating CLI */
#define LGI$_NOTVALID		0X00D3803C  /* User authorization failure */
#define LGI$_FILEACC		0x00D38044  /* Error accessing SYSUAF */
#define LGI$_CAPTIVE		0X00D38074  /* Quals not allowed in capt acc. */
#define LGI$_BADHOUR		0X00D3807C  /* Bad login time */
#define LGI$_USEREXC		0X00D38084  /* Too many processes/username */
#define LGI$_ACNTEXC		0X00D3808C  /* Too many processes/account n. */
#define LGI$_BADDAY		0X00D38094  /* Bad login day */
#define LGI$_RESTRICT		0X00D3809C  /* Bad login source */
#define LGI$_EVADE		0X00D380B4  /* Break-in evasion in effect */
#define LGI$_DEFCLI		0X00D380BC  /* No CLI parameters */
#define LGI$_ACNTEXPIR		0X00D380C4  /* Account has expired */
#define LGI$_PWDEXPIR		0X00D380CC  /* Password has expired */
#define LGI$_DISRECONNECT	0X00D380DC  /* No reconnections allowed */
#define LGI$_CLITBLFAIL		0X00D380E4  /* Error activating CLI tables */
#define LGI$_NOSUCHUSER		0X00D380F4  /* User doesn't exist */
#define LGI$_INVPWD		0X00D380FC  /* Invalid password */
#define LGI$_EXLICENSE		0X00D38104  /* Licensed # of users exceeded */
#define LGI$_DISUSER		0X00D3810C  /* Account is disabled */
#define LGI$_AUTOLOGIN		0X00D38114  /* Account is auto-login only */
#define LGI$_INVINPUT		0X00D3811C  /* Invalid SYS$INPUT device */
#define LGI$_NOTMODEM		0X00D38124  /* No modem connection */
#define LGI$_DECWCAPTIVE	0X00D38144  /* No DECW login with capt. acc. */
#define LGI$_NOVAXCLUSTER	0X00D3814C  /* No VMSCLUSTER license loaded */
#define LGI$_LICNOTREQ		0X00D38159  /* License check not required */
#define LGI$_LOGOPRCON		0X00D38169  /* Login allowed from OPA0: */

/* Message codes for SECSRV facility.
   The module SECSRVMSGDEF doesn't exist for C, so we take these
   definitions from the $SECSRVMSGDEF module from STARLET.MLB. */

#define SECSRV$_INTRUDER	  0x06EE97C3	/* Matching intruder found */
#define SECSRV$_SUSPECT		  0x06EE97CB	/* Matching suspect found */
#define SECSRV$_NOSCANNEDINTRUDER 0x06EE97E3	/* No matching intruder foun=
d */
#define SECSRV$_NOSUCHUSER	  0x06EEC652	/* No matching user found */
#define SECSRV$_NOSUCHPROXY	  0x06EEC672	/* No matching proxy found */
#define SECSRV$_SERVERNOTACTIVE	  0x06EEC6FA	/* Security server not rung.=
 */
#endif

=0C---------------------->>> #21: _GETQUO.MAR <<<----------------------


		.title	_GETQUO - Get values for quota checks
		.ident	'BOL-V1.0/OCT-95'

		; This routine is used to scan the process vector
		; array and count all processes whose username
		; match the given username and account name the
		; given account name. This is used to perform the
		; maximum username and account name quota checks.
		;
		; For the username check, network processes are
		; counted separately, since the first four network
		; jobs are ignored (see module CHKQUO). For the
		; account name check, network processes are always
		; ignored.
		;
		; Processes with the PCB$M_NOACNT (no accounting
		; for this process) bit set in PCB$L_STS and
		; subprocesses (non-zero PCB$L_OWNER) are ignored
		; as well.
		;=20
		; Input parameters:
		;
		; 4(ap): the account name as 8-byte, blank-filled string
		; 8(ap): the username as 12-byte, blank-filled string
		; 12(ap): address of account name counter
		; 16(ap): address of username counter for non-network jobs
		; 20(ap); address of username counter for network jobs
		;
		; Returns:
		;
		; always SS$_NORMAL.
		;
		; NOTE: This routine runs in kernel mode, IPL 0. It doesn't
		;       lock any MUTEX. You may want to change this:
		;
		;       o - Lock the code into working set (on Alpha, also
		;	    lock the approbiate linkage section)
		;
		;	o - Lock the SCHED mutex. This will elevate IPL to 8
		;
		;	o - Run this code
		;
		;	o - Unlock the SCHED mutex and set IPL back to 0
		;
		;	o - Unlock the code (and linkage section) from working
		;	    set
		;
		; I havn't done this here for the reason of shortness.

		$pcbdef		; PCB definitions
		$jibdef		; JIB definitions

		; =0C
		.entry	_GETQUO, ^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
		movab	@#exe$sigtoret,(fp)	; Establish condition handler
		movl	4(ap), r10		; Get account name string
		movl	8(ap), r11		; Get username string
		clrl	@12(ap)			; Clear all
		clrl	@16(ap)			; counters
		clrl	@20(ap)			; first
		movl	@#sch$gl_pcbvec,r6	; Start of PCB vector array
		movzbl	#2, r7			; Skip NULL and SWAPPER
10$:		cmpl	r7, @#sch$gl_maxpix	; Already on end of array?
		beql	40$			; Yes, exit
		movl	(r6)[r7],r8		; Get next slot
		cmpl	r8,(r6)			; Unused PCB slot?
		beql	30$			; Yes, drop it
		bitl	#pcb$m_noacnt,pcb$l_sts(r8) ; NOACNT process?
		bneq	30$			; Yes, drop it
		tstl	pcb$l_owner(r8)		; Subprocess ?
		bneq	30$			; Yes, drop it
		movl	pcb$l_jib(r8),r9	; Get JIB address
		bitl	#pcb$m_netwrk,pcb$l_sts(r8) ; Network job?
		bneq	20$			; Yes, skip account name check
		cmpc3	#jib$s_account,(r10),jib$t_account(r9) ; Compare names
		bneq	20$			; Not the same
		incl	@12(ap)			; Increment account counter
20$:		cmpc3	#jib$s_username,(r11),jib$t_username(r9); Comp. names
		bneq	30$
		bitl	#pcb$m_netwrk,pcb$l_sts(r8) ; Network job?
		beql	25$			; No
		incl	@20(ap)			; Yes, increment network counter
		brb	30$			; and try next
25$:		incl	@16(ap)			; Incr non-network counter
30$:		incl	r7			; Increment array offset
		brb	10$			; and try next
40$:		movzbl	#1, r0			; OK
		ret				; and return

		.end

=0C---------------------->>> #22: _NAM_2_ADD.MAR <<<---------------------=
-


		.title		_NAM_TO_ADD - Convert nodename to node address
		.ident		'BOL-V1.0/OCT-95'

		.library	"SYS$SHARE:LIB"

		; This routine converts a DECnet nodename into
		; the corresponding node address. This is done
		; by assigning a device to the _NET0: network
		; template device and issuing a QIO with the
		; IO$_ACPCONTROL function on the returned
		; channel. The following arguments are further
		; used:
		;
		; P1 =3D Address of a block containing command
		;      information (NFB$_xxx symbols);
		;
		; P2 =3D Address of a descriptor containing the
		;      key value (in our case, the name of
		;      node which we want the address from);
		;
		; P4 =3D Address of a descriptor pointing to
		;      a buffer which receives the obtained
		;      information (in our case, a longword
		;      for the node address).
		;
		; Note that this interface to DECnet is
		; undocumented. Thanks to Wolfgang J. Moeller
      		; (moeller@gwdvms.dnet.gwdg.de) for giving me
		; this program as an example.
		;=20
		; Input parameters:
		;
		; 4(ap): address of a descriptor pointing to
		;        the node name
		; 8(ap): address of a longword which receives
		;        the node address
		;
		; Returns:
		;
		; SS$_NORMAL......translation was successful
		;
		; SS$_ENDOFFILE...translation failed, nodename is unknown
		;
		; Any other return code given by the SYS$QIOW system service
		; and the DECnet network programming interface.

		$iodef		; IO$_xxxx function definitions
		$nfbdef		; NFB command buffer definitions

		; =0C
		.psect	$$DATA, wrt, noexe, noshr

		; NFB command buffer

NFB_BUF:	.byte	NFB$C_FC_SHOW	; NFB$B_FCT: Function =3D SHOW
		.byte	NFB$M_NOCTX	; NFB$B_FLAGS: Flags =3D no search context
		.byte	NFB$C_DB_NDI	; NFB$B_DATABASE: Database =3D nodes
		.byte	NFB$C_OP_EQL	; NFB$B_OPER: Operation =3D match if equal
		.long	NFB$C_NDI_NNA	; NFB$L_SRCH_KEY: Search key =3D nodename
		.long	0		; NFB$L_SRCH2_KEY: no second key
		.byte	0		; NFB$B_OPER2: no second key
		.byte	0		; NFB$B_MBZ1: must be zero
		.word	0		; NFB$W_CELL_SIZE: default cell size
		.long	NFB$C_NDI_TAD	; NFB$L_FLDID: Return value =3D address
		.long	NFB$C_ENDOFLIST	; Marks end of return list
NFB_LEN =3D	. - NFB_BUF

		; NFB descriptor; this address is passed as
		; parameter P1 the QIO IO$_ACPCONTROL call

NFB_DSC:	.long	NFB_LEN
		.long	NFB_BUF

		; Key buffer. This buffer contains the name
		; of the node which we want to look for.

KEY_BUF:	.long	0	; "p4_count"
NODLEN:		.word	0	; length of input nodename (1..6)
NODNAM:		.blkb	6	; room for node name, zerofill
		.long	0	; "srch2"
		.word	0	; "start"
		.blkb	NFB$C_CTX_SIZE	; context size
KEY_LEN =3D	. - KEY_BUF

		; Key descriptor. It is passed as
		; parameter P2 the QIO IO$_ACPCONTROL call

KEY_DSC:	.long	KEY_LEN
		.long	KEY_BUF

		; Return buffer to receive the obtained information.

RET_BUF:	.blkl	1
RET_LEN =3D	. - RET_BUF

		; Return descriptor. It is passed as
		; parameter P4 the QIO IO$_ACPCONTROL call

RET_DSC:	.long	RET_LEN
		.long	RET_BUF

NETNAM:		.ascid	"NET:"		; Network template device name

NETCHAN:	.blkw	1		; Network device channel

IOSB:		.blkw	4		; I/O status block

		; =0C
		.psect		$$CODE, exe, shr, nowrt

		.entry		_nam_2_add, ^m<r2,r3,r4,r5>
		movq		@4(ap), r0	; Get nodename length
		cmpw		r0, #6		; Greather 6?
		blequ		10$		; Not allowed
		movzwl		#ss$_badparam, r0
		ret
10$:		movw		r0, NODLEN	; Update length field
		movc5		r0, (r1), #0, #6, NODNAM ; Copy nodename
		$assign_s	chan	=3D NETCHAN,-	 ; Assign channel
				devnam	=3D NETNAM	 ; to NET: device
		blbs		r0, 20$
		ret
20$:		movaq		NFB_DSC, r2	; r2 points to NFB descr.
		movaq		KEY_DSC, r1	; r1 points to key descr.
		movaq		RET_DSC, r0	; r0 points to ret descr.
		$qiow_s		chan	=3D NETCHAN,-	; Issue QIOW call
				func	=3D #io$_acpcontrol,- ; ACP is called
				iosb	=3D IOSB,-	; IOSB
				p1	=3D (r2),-	; NFB descr. address
				p2	=3D r1,-		; key descr. address
				p4	=3D r0		; return descr. addr.
		pushl		r0		; Save return status
		$dassgn_s	chan	=3D NETCHAN ; Deassign I/O channel
		movl		(sp)+, r0	; Restore return status
		blbc		r0, 30$		; Error? Exit
		movzwl		IOSB, r0	; Get IOSB status
		blbc		r0, 30$		; Error? Exit
		movl		RET_BUF, @8(ap)	; Return address to user
30$:		ret				; OK

		.end

----------------------->>> END OF MAIL <<<----------------------


--------------15FB59E21CFB--

