Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Elevate privileges in a program

10 views
Skip to first unread message

Mark Hemker

unread,
Jul 25, 2003, 7:49:59 AM7/25/03
to
I'm working with some of our programmers on a new product and we have
run into a stumbling block with regards to needing privileges for
certain system function calls. What we have is a PASCAL program that
needs to be able to make several function calls where the code in the
functions requires elevated privileges. We looked at installing a
shareable image with these functions, but as you know that won't work
We also looked into writing a User-Written System Service and
discovered that some of system service calls that we need can't be
used in a UWSS.

To take this in baby steps, we have cut back to just trying to get one
of the functions implemented. This one function really just issues a
series of about 5 DCL commands that work with a very protected
directory and the files in it. We are currently creating a standalone
image that issues the needed commands and I can install that with the
necessary privileges. I know this isn't the best solution because now
anyone can run the image from DCL and get to the protected directory.
For this standalone image, we are looking writing it in C so that we
can use the SYSTEM() function or one of the EXEC() functions. We are
planning to use LIB$SPAWN from the PASCAL code to run this new image.
Is there a PASCAL equivalent to SYSTEM() or EXEC() or is there
something better?

If anyone has any suggestions, I would love to hear them.

By the way, if you reply via private email, please use
mhe...@remember.com since that is my work address.

Thanks,
Mark Hemker
hem...@insightbb.com

Stanley F. Quayle

unread,
Jul 25, 2003, 9:02:11 AM7/25/03
to
On 25 Jul 2003 at 11:49, Mark Hemker wrote:
> What we have is a PASCAL program that
> needs to be able to make several function calls where the code in the
> functions requires elevated privileges.
[...]

> This one function really just issues a
> series of about 5 DCL commands that work with a very protected
> directory and the files in it.
[...]

> we are looking writing it in C so that we can use the SYSTEM()
> function or one of the EXEC() functions. We are planning to use
> LIB$SPAWN from the PASCAL code to run this new image.

The SYSTEM and LIB$SPAWN calls create a subprocess, which generally
gets the default privileges for your username. You can create and
control the privileges of a subprocess by calling SYS$CREPRC instead.
--Stan Quayle
Quayle Consulting Inc.

----------
Stanley F. Quayle, P.E. N8SQ +1 614-868-1363 Fax: +1 614 868-1671
8572 North Spring Ct. NW, Pickerington, OH 43147
Preferred address: st...@stanq.com http://www.stanq.com


Larry Kilgallen

unread,
Jul 25, 2003, 10:43:59 AM7/25/03
to
In article <5752ivskpr05bvsve...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
> I'm working with some of our programmers on a new product and we have
> run into a stumbling block with regards to needing privileges for
> certain system function calls. What we have is a PASCAL program that
> needs to be able to make several function calls where the code in the
> functions requires elevated privileges. We looked at installing a
> shareable image with these functions, but as you know that won't work
> We also looked into writing a User-Written System Service and
> discovered that some of system service calls that we need can't be
> used in a UWSS.

You would get a better quality answer by specifying the system services
involved. There are _many_ ways to introduce vulnerabilities to a VMS
system trying to do this sort of thing, and a User-Written System Service
is a method of avoiding most of those problems.

> For this standalone image, we are looking writing it in C so that we
> can use the SYSTEM() function or one of the EXEC() functions. We are
> planning to use LIB$SPAWN from the PASCAL code to run this new image.
> Is there a PASCAL equivalent to SYSTEM() or EXEC() or is there
> something better?

SYSTEM() and EXEC() are creations of the C Runtime Library and are thus
not going to be so stable as VMS system services.

95% of the time when people try something like this they introduce a
security hole.

Adrian Birkett

unread,
Jul 25, 2003, 11:05:50 AM7/25/03
to
Mark,

You can only elevate a processes privilege if that user has the privilege
authorized in UAF using the SYS$SETPRV service (ok, grandmother & eggs, I
know). If your users only have minimum privileges authorized you have a
problem. You can possibly get round this by installing the image with the
required privileges which is the simplest and more manageable method.
Other methods might include a seperate installed program reading and
writing to a mailbox of some sort.

It is always good practise, in my mind, to deny privileges to users unless
they can justify a reason for them. Simply using the phrase 'because I
need them' isn't good enough. If there is no way round it, and this app
needs to use a privileged service, I'd use the installed image route.

Ade

JF Mezei

unread,
Jul 25, 2003, 11:33:20 AM7/25/03
to
Mark Hemker wrote:
>
> I'm working with some of our programmers on a new product and we have
> run into a stumbling block with regards to needing privileges for
> certain system function calls.

Which privileges do you need ?

If it is just a question of accessing files, then you could do it easily
without privileges by using ACLs on the files to grant access. VMS also has
the ability to grant an image and identifier, so anyone running that image
temporarily gains that identifier (providing access to certain files). But
this must be enable on the disk first.

Also, which DCL command do you require when you spawn a subprocess ? you could
probably do this with system calls from Pascal.

Another possibility is for you to use user written system services and find
other ways to accomplish what you needed with those routines that can't be
used in such a routine.

bri...@encompasserve.org

unread,
Jul 25, 2003, 12:02:21 PM7/25/03
to
In article <3F20F213.12157.794F7A6@localhost>, "Stanley F. Quayle" <st...@stanq.com> writes:
> On 25 Jul 2003 at 11:49, Mark Hemker wrote:
>> What we have is a PASCAL program that
>> needs to be able to make several function calls where the code in the
>> functions requires elevated privileges.
> [...]
>> This one function really just issues a
>> series of about 5 DCL commands that work with a very protected
>> directory and the files in it.
> [...]
>> we are looking writing it in C so that we can use the SYSTEM()
>> function or one of the EXEC() functions. We are planning to use
>> LIB$SPAWN from the PASCAL code to run this new image.
>
> The SYSTEM and LIB$SPAWN calls create a subprocess, which generally
> gets the default privileges for your username. You can create and
> control the privileges of a subprocess by calling SYS$CREPRC instead.

LIB$SPAWN takes the _current_ privileges of the parent and makes
those the _authorized_ privileges of the child.

The child can then use SYS$SETPRV or $ SET PROCESS /PRIV to activate
those latent privileges.

BE WARNED:

Unless the parent is running from a very tightly controlled environment,
it is possible for a malicious user to hijack the enhanced privileges,
causing his own code to run with enhanced privilege in place of yours.

*** LIB$SPAWN and SYSTEM are NOT privilege-safe ***

The available attacks are varied and some are fairly subtle. Defensive
coding style in the spawned code is utterly irrelevant for some of
the attacks. The attacker already owns you before your code ever
gets control (and your code never gets control).

VERY careful and knowledgeable defensive coding in the parent can
do a pretty good job of foiling these attacks. A good start is
to turn off propagation of DCL symbols and process logicals and to
check for translations of SYS$SYSTEM, SYS$SYSROOT, SYS$COMMON and
LOGINOUT in LNM$FILE_DEV (to make sure those translations either do
not exist or are at executive mode or better). That will still
leave you vulnerable to some exploits of race conditions and you still
need to code defensively in the subprocess (paying special attention
to possible manipulations of the job logical name table). If you then
audit aggressively you have a good chance of catching the bad guy before
he catches you.

I've never carefully investigated the feasibility of an attack on
the mailbox communication stream between parent and spawned child.
So I don't know whether it is neccessary (or possible) to foil
an attack targetted there.

I think you're safe against command language table manipulation. The
subprocess gets a copy of the base command tables rather than
a copy of the parent's current command tables. If I remember right.
It's been a very long time.

John Briggs

VAXman-

unread,
Jul 25, 2003, 12:03:15 PM7/25/03
to
In article <5752ivskpr05bvsve...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
>I'm working with some of our programmers on a new product and we have
>run into a stumbling block with regards to needing privileges for
>certain system function calls. What we have is a PASCAL program that
>needs to be able to make several function calls where the code in the
>functions requires elevated privileges. We looked at installing a
>shareable image with these functions, but as you know that won't work
>We also looked into writing a User-Written System Service and
>discovered that some of system service calls that we need can't be
>used in a UWSS.

Which service(s)?

--
VAXman- OpenVMS APE certification number: AAA-0001 VAXman(at)TMESIS(dot)COM

"Well my son, life is like a beanstalk, isn't it?"

Hoff Hoffman

unread,
Jul 25, 2003, 12:45:12 PM7/25/03
to
In article <5752ivskpr05bvsve...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
:I'm working with some of our programmers on a new product and we have

:run into a stumbling block with regards to needing privileges for
:certain system function calls. What we have is a PASCAL program that
:needs to be able to make several function calls where the code in the
:functions requires elevated privileges. We looked at installing a
:shareable image with these functions, but as you know that won't work

Correct. (For those that are not familiar with shareable images
and privileged shareable images, please see the shareable image
cookbook referenced in the OpenVMS FAQ.)

:We also looked into writing a User-Written System Service and


:discovered that some of system service calls that we need can't be
:used in a UWSS.

I here assume you are seeing:

NOSHRIMG, privileged shareable image cannot have outbound calls

Everything referenced from a UWSS must be trusted code. Outbound
references to untrusted (unprotected) shareable images are verboten.

See the support article (available via AskQ, see the OpenVMS FAQ
for pointers to AskQ) "SYSTEM-F-NOSHRIMG Error When A User-Written
System Service Is Called".

To find which shareables the code is referencing, try this:

$ analyze/image/output=x.tmp imagename.exe
$ search/exact/window=(0,20) x.tmp "Shareable"

SYS$PUBLIC_VECTORS and SYS$BASE_IMAGE are OK, and references to
other shareable images will typically trigger the NOSHRIMG error.
You can use LINK/NOSYSSHR to help capture and to eliminate these
references.

The abovementioned information is similar to information in the AskQ
article: "NOSHRIMG Privileged Shareable Image Cannot Have Outbound
Calls".


:To take this in baby steps, we have cut back to just trying to get one


:of the functions implemented. This one function really just issues a
:series of about 5 DCL commands that work with a very protected
:directory and the files in it.

This particular use is trivially easy with subsystem identifiers,
and the subsystem identifiers avoid most of the risks that are
involved with the "big hammer" approach using enhanced privileges.

: We are currently creating a standalone


:image that issues the needed commands and I can install that with the
:necessary privileges. I know this isn't the best solution because now
:anyone can run the image from DCL and get to the protected directory.

Everyone can use a UWSS, too.

:For this standalone image, we are looking writing it in C so that we


:can use the SYSTEM() function or one of the EXEC() functions. We are
:planning to use LIB$SPAWN from the PASCAL code to run this new image.

Ugh. That's slow, and probably not necessary.

:Is there a PASCAL equivalent to SYSTEM() or EXEC() or is there
:something better?

system() is lib$spawn(). vfork() and exec*() are not something
that you will likely want to tangle with, well, not unless you are
or wish to become very familiar with the full and somewhat arcane
meaning of this part of the C language and also with the OpenVMS
implementation of the fork-related process-level processing.

:If anyone has any suggestions, I would love to hear them.

Your current approach is a hugely BAD IDEA. (No offense is intended.)

I would first look to subsystem identifiers -- depending on the
particulars of the access(es) required -- and I would then look
to using an installed image. I would then look to the persona
services, and then to DECnet or IP server tasks running with
privileges, and then to an installed image. I would not bother
to implement a UWSS that grants privileges -- I'd issue every
user on the system the privilege(s) granted first, since that is
exactly what the UWSS-based approach would effectively provide.

Adding privileges via user-written system service is certainly
possible, but it tends to create monstrously-large security
holes.

If you do start writing inner-mode code (as a UWSS requires),
you cannot call user-mode RTL routines nor the user-mode C RTL.
Most inner-mode code uses LINK/NOSYSSHJRRYSEXE, with /NOSYSSHR
locking out the user-mode access and with /SYSEXE enabling access
to the C kernel-mode RTL and to the kernel entry points; to the
SYS$BASE_IMAGE definitions.

Related Ask The Wizard topics include (1547), (1073), (1719),
(2524), (2774), (5172), (5639), (5895), (6056), (6363), (7368),
(7870), and (numerous) others.

http://www.hp.com/go/openvms/wizard/

I would also strongly recommend a trip through the OpenVMS Security
Manual -- whenever writing privileged-mode code, you must and have
to assume that your code will be specifically sought after and will
be specifically targeted by any nefarious-minded user or cracker.


---------------------------- #include <rtfaq.h> -----------------------------
For additional, please see the OpenVMS FAQ -- www.hp.com/go/openvms/faq
--------------------------- pure personal opinion ---------------------------
Hoff (Stephen) Hoffman OpenVMS Engineering hoff[at]hp.com

Chris Scheers

unread,
Jul 25, 2003, 1:32:10 PM7/25/03
to


It's not clear what privileged operations you want to do.

You mention a "protected directory". If accessing this is all you need
to do, you probably don't need anything special in your code.

If you want to provide access to the "protected directory" to a set of
users, you can easily do this with identifiers granted to the users and
correctly setting the ownership and/or ACLs on the directory and its
files.

If you want to provide access to the "protected directory" to a set of
programs (whoever runs them), look into protected subsystems.

Of course, a combination of the two can be used so that only certain
users can run the protected programs.

Good luck!

-----------------------------------------------------------------------
Chris Scheers, Applied Synergy, Inc.

Voice: 817-237-3360 Internet: ch...@applied-synergy.com
Fax: 817-237-3074

Mark Hemker

unread,
Jul 25, 2003, 2:14:11 PM7/25/03
to
Kilg...@SpamCop.net (Larry Kilgallen) wrote in message news:<H2QYa+...@eisner.encompasserve.org>...

> In article <5752ivskpr05bvsve...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
> > I'm working with some of our programmers on a new product and we have
> > run into a stumbling block with regards to needing privileges for
> > certain system function calls. What we have is a PASCAL program that
> > needs to be able to make several function calls where the code in the
> > functions requires elevated privileges. We looked at installing a
> > shareable image with these functions, but as you know that won't work
> > We also looked into writing a User-Written System Service and
> > discovered that some of system service calls that we need can't be
> > used in a UWSS.
>
> You would get a better quality answer by specifying the system services
> involved. There are _many_ ways to introduce vulnerabilities to a VMS
> system trying to do this sort of thing, and a User-Written System Service
> is a method of avoiding most of those problems.
>

I need to use $GETUAI to validate a username and password.



> > For this standalone image, we are looking writing it in C so that we
> > can use the SYSTEM() function or one of the EXEC() functions. We are
> > planning to use LIB$SPAWN from the PASCAL code to run this new image.
> > Is there a PASCAL equivalent to SYSTEM() or EXEC() or is there
> > something better?
>
> SYSTEM() and EXEC() are creations of the C Runtime Library and are thus
> not going to be so stable as VMS system services.
>
> 95% of the time when people try something like this they introduce a
> security hole.

I am trying to avoid creating any security holes and I just haven't
had much luck finding a way of accomplishing my needed goal without
creating one.

Thanks for the help. I am also looking into using protected
subsystems, but we still run into an issue with the user being able to
run the program from DCL and gaining access to the protected
directory.

Let me explain what the protected directory is used for:
-Copy a file from a public directory into the protected directory.
-Run a program that manipulates the file in the protected directory
and creates a new file.
-Delete the input file we just manipulated.
-Queue the resulting file to a print queue with /DELETE so that the
file is automatically deleted.

We have a requirement that the files not be accessible to the user
except through our program and that is why we have all of the hoops to
jump through.

Thanks,
Mark

Hoff Hoffman

unread,
Jul 25, 2003, 3:03:48 PM7/25/03
to
In article <df640d0b.03072...@posting.google.com>, mhe...@remember.com (Mark Hemker) writes:
:Kilg...@SpamCop.net (Larry Kilgallen) wrote in message news:<H2QYa+...@eisner.encompasserve.org>...

:> You would get a better quality answer by specifying the system services


:> involved. There are _many_ ways to introduce vulnerabilities to a VMS
:> system trying to do this sort of thing, and a User-Written System Service
:> is a method of avoiding most of those problems.
:>
:
:I need to use $GETUAI to validate a username and password.

... ...

:I am trying to avoid creating any security holes and I just haven't


:had much luck finding a way of accomplishing my needed goal without
:creating one.

You are correct; I expect you have implemented a security hole with
your $getuai code. Why are you checking the username and password?
(If you want to be part of the Trusted Computing Base (TCB) as this
password verification implies -- of the operating system kernel and
the privileged applications -- then you are a target, and performing
a password check certainly makes you a target. Big-time.)

:I am also looking into using protected


:subsystems, but we still run into an issue with the user being able to
:run the program from DCL and gaining access to the protected
:directory.

What (specific) issue(s)? If the image has the subsystem identifier,
it has the access -- or the denial, since identifiers can also be used
to negate access -- provided by the identifier.

:Let me explain what the protected directory is used for:


: -Copy a file from a public directory into the protected directory.

I assume this is a case where you want the privileged code
to pull the code over.

: -Run a program that manipulates the file in the protected directory


:and creates a new file.

Okfine. DECnet task-to-task can provide this capability easily.
Subsystem identifiers can work, too. Realize that if you are running
code provided by the user from a privileged context, that's, well, a
large security hole.

: -Delete the input file we just manipulated.


: -Queue the resulting file to a print queue with /DELETE so that the
:file is automatically deleted.

Usually via a $sndjbc[w] call, if this is a program.

Speaking of queues, that's another solution here -- a custom symbiont.
Though you still need to be exceedingly careful not to run untrusted
code from a privileged context, symbiont or otherwise. With the custom
symbiont, the user would submit the file to a server queue, and the
symbiont would then process it.

:We have a requirement that the files not be accessible to the user


:except through our program and that is why we have all of the hoops to
:jump through.

Callable convert from an installed image is another option; callable
convert is effectively a callable COPY command API.

--

I would think you will want to describe the problem and its background
in rather more detail, rather than proposing a solution first and working
backwards from that information. (What I've read so far, I don't fully
understand. For instance, what does the privileged pre-processing do?
What is the user's invocation context of the resulting executable image?
Privileged? Unprivileged? This whole processing sequence looks unusual.)

JF Mezei

unread,
Jul 25, 2003, 3:36:12 PM7/25/03
to
Mark Hemker wrote:
> -Queue the resulting file to a print queue with /DELETE so that the
> file is automatically deleted.

Do print symbionts have the equivalent of SYSPRV to access the fille for print
and subsequent delete ?

Be careful. If User A submits a print job, you have to make sure that the file
being submitted isn't owned by user A (so that he can't go do a SHOW
ENTRY/FULL and then copy the file), on the other hand, you also need to make
sure that if the file is created under owner "B" but submitted by A, that the
print symbiont will accept to print that file if A doesn't have access to that file.

JF Mezei

unread,
Jul 25, 2003, 3:50:59 PM7/25/03
to
Hoff Hoffman didn't write:
> :I need to use $GETUAI to validate a username and password.

Gee Hoff, I would have though that by now, you'd know how to do that ? :-)
:-) :-) :-) :-) :-)

From the manual:

Required Access or Privileges

Use the following list to determine the privileges required to use the $GETUAI
service:

BYPASS or SYSPRV---Allows access to any record in the user authorization file
(UAF).
GRPPRV---Allows access to any record in the UAF whose UIC group matches that
of the requester.
No privilege---Allows access to any UAF record whose UIC matches that of the
requester.
You need read access to the UAF to look up any information other than your
own.


So, if you have an application which runs under usernam,e John Doe and wants
to verify John Doe's password, then the application doesn't need ant privileges.

If you have an application which wants to allow John Doe to check Jane Smith's
password, then you also need to look into the routines that will generate
audit alarms and intrusion detection.

Aren't there newer ACME* routines that allow that ? (although they would
probably be unusable if available only on Alpha).

Larry Kilgallen

unread,
Jul 25, 2003, 7:05:58 PM7/25/03
to
In article <df640d0b.03072...@posting.google.com>, mhe...@remember.com (Mark Hemker) writes:
> Kilg...@SpamCop.net (Larry Kilgallen) wrote in message news:<H2QYa+...@eisner.encompasserve.org>...
>> In article <5752ivskpr05bvsve...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
>> > I'm working with some of our programmers on a new product and we have
>> > run into a stumbling block with regards to needing privileges for
>> > certain system function calls. What we have is a PASCAL program that
>> > needs to be able to make several function calls where the code in the
>> > functions requires elevated privileges. We looked at installing a
>> > shareable image with these functions, but as you know that won't work
>> > We also looked into writing a User-Written System Service and
>> > discovered that some of system service calls that we need can't be
>> > used in a UWSS.
>>
>> You would get a better quality answer by specifying the system services
>> involved. There are _many_ ways to introduce vulnerabilities to a VMS
>> system trying to do this sort of thing, and a User-Written System Service
>> is a method of avoiding most of those problems.
>>
>
> I need to use $GETUAI to validate a username and password.

If you are doing this on Alpha, use the $ACM system service under V7.3-1
or greater to do this safely. I believe it requires no privileges.

>> 95% of the time when people try something like this they introduce a
>> security hole.
>
> I am trying to avoid creating any security holes and I just haven't
> had much luck finding a way of accomplishing my needed goal without
> creating one.

$ACM was provided because of the difficulty of doing this.

> Thanks for the help. I am also looking into using protected
> subsystems, but we still run into an issue with the user being able to
> run the program from DCL and gaining access to the protected
> directory.
>
> Let me explain what the protected directory is used for:
> -Copy a file from a public directory into the protected directory.
> -Run a program that manipulates the file in the protected directory
> and creates a new file.
> -Delete the input file we just manipulated.
> -Queue the resulting file to a print queue with /DELETE so that the
> file is automatically deleted.
>
> We have a requirement that the files not be accessible to the user
> except through our program and that is why we have all of the hoops to
> jump through.

"Protected Subsystems" is the specific nature of a particular VMS feature
on both VAX and Alpha. It will allow you to do what you described there
just fine, but it would seem you need to read and understand documentation
related to protected subsystems.

But what you describe there has nothing at all to do with validating a
username and password. Do you really have two problems to solve ?

David J. Dachtera

unread,
Jul 25, 2003, 11:36:43 PM7/25/03
to
Mark Hemker wrote:
> [snip]

> I need to use $GETUAI to validate a username and password.

Hasn't VMS already done that?

> [snip]


> Let me explain what the protected directory is used for:
> -Copy a file from a public directory into the protected directory.
> -Run a program that manipulates the file in the protected directory
> and creates a new file.
> -Delete the input file we just manipulated.

The COPY, then, is redundant. Can't the program open the original file
in place ACCESS READ, ALLOW MODIFY (equiv. to DCL
OPEN/READ/SHARE=WRITE)?

> -Queue the resulting file to a print queue with /DELETE so that the
> file is automatically deleted.

There's another way (one of many, I'm sure) to do that: set the print
device of the target queue /SPOOLED and open the device directly. The
system will "spool" the output to a file with no directory entry (which
I believe may be owned by the system, but not sure just now and don't
want to take the time at this hour to set up a test). Upon the program
closing the file, the file will be entered into the queue associated
with the spooled device. A file with no directly entry introduces a good
number of "hoops to jump through" to find it, much less attempt to
access it by FID.

> We have a requirement that the files not be accessible to the user
> except through our program and that is why we have all of the hoops to
> jump through.

INSTALLing the program with privilege is not acceptable? ...even from a
CAPTIVE account?

Not sure if that would fit your security model, but it would sure make
the whole task a lot easier to accomplish.

--
David J. Dachtera
dba DJE Systems
http://www.djesys.com/

Unofficial Affordable OpenVMS Home Page:
http://www.djesys.com/vms/soho/

Richard Maher

unread,
Jul 26, 2003, 5:17:30 AM7/26/03
to
Hi Mark,

UWSSs are definitely the right way to go. (Exactly why Hoff continues to
persue his Nanny-State/Ferenheit-451 agenda of banning people from using
UWSSs and in particular the MACRO compiler is beyond me! Certainly doesn't
bode well for how these facilities will be implemented on Itanium :-()

Simply drop the /PROTECT and /NOSYSSHR qualifiers on your $LINK and you now
have the ability to call whatever RTL you like. I believe it's
SECURESHRP.EXE if you want $GETUAI. That's the easy part. You are now at
your most vulnerable!!! It is up to you to protect your working-storage and
I/O channels and everything else from outer-mode corruption and
exploitation. (See the COLLECT and PROTECT linker options bellow)

So now you've made sure that your memory is protected from a dodgy or
mallicious user-mode pointers and all *your* channels are $ASSIGNed and
$QIOed at EXEC mode but how can you vouch for $getuai or other RTL routine?
How can you trust them to do the right thing? What if a hacker is writing
$QIOs to a random channel selector seeing if he gets a result 'cos PRIVs
were used to access SYSUAF but the channel was mistakenly open in USER mode?
What if *they* forget to protect their memory?

All wonderful questions which undoubtedly can be answered by the VMS and Rdb
engineering people who do this every day. (Please run an analyze/image over
a couple of privileged shareables (eg: RDB$COSIP) and see *all* of the
plethora of other RTLs that these images are linked against. So don't do as
they do just do as they say? I don't think so. *SOME OF THESE LAND MINES
EVEN CALL OUT to CRTL!!!* Let's all pray that it's not from inner-mode!)

Anyway please search through the COV archives (search for blade guard) for
other fruitless discussions on this subject. I have asked for guidence on
dropping /PROTECT (but still being secure) hundreds of bloody times without
any joy. I even dragged myself across North London to a "Hints and Kinks"
session that supposed to discuss this stuff but the room was packed with
System Managers and not Developers and tha air-conditioning was off so you
know what a hoot that was :-)

I'm also about to post another UWSS example that let's an unprivileged user
wait until a file is created in a directory!

(Did you know that any user can do a $dir/fid on any file. I thought telling
you whether or not a file exists (if you don't have priv) was wrong? See, my
RTL with tell you the filename that I'm waiting for but if (when it gets
created) you don't have priv to see it then your AST will fire and give you
SS$_NOPRIV in the IOSB. But that sought of defeats the purpose don't you
think?)

Regards Richard Maher


$ on warning then exit
$ if .not. f$privilege("cmkrnl,sysprv,pfnmap,bypass") then goto no_priv
$ if f$getsyi("arch_name") .nes. "Alpha" then goto no_vax
$!
$ create maher$share.mar
;++
;
; (c) Copyright Tier3 Software. All rights reserved.
;
; Ownership of this software and all associated intellectual
; property rights remain vested in Tier3 Software Ltd. This
; software or any other copies thereof may not be provided
; or otherwise made available to any other person.
;
; Do not remove this copyright notice.
;
; Author: Richard Maher
;
;--
.macro define_service,name,narg=0,mode=exec,?endmacro

'mode'_routine_count='mode'_routine_count+1

.call_entry max_args=narg, -
home_args=true, -
label=name

.save_psect local_block

.psect 'mode'_list

.address name

.restore_psect

.if not_equal narg

cmpb (ap),#narg
bgeq endmacro
movzwl #ss$_insfarg,r0
ret

endmacro:

.endc
.endm

.title maher$share - Demo User Written System Services
.ident "V2.0"

.library "sys$library:lib.mlb"

$plvdef
$prvdef
$psldef
$dscdef
$ssdef
$uaidef

usrnam_max=12
out_len=94
enable=1
disable=0

kernel_routine_count=0
exec_routine_count=0

.psect exec_list,pic,con,rel,lcl,noshr,noexe,rd,nowrt,long
exec_table:

.psect kernel_list,pic,con,rel,lcl,noshr,noexe,rd,nowrt,long
kernel_table:

.page
.psect _maher$data,pic,con,rel,lcl,noshr,noexe,rd,wrt,quad

uai_ctx:
.long 0

uai_lst:
.word 32, uai$_defdev
.address -
def_dev
.long 0

.word 64, uai$_defdir
.address -
def_dir
.long 0

.long 0

def_dev:
.blkb 32
def_dir:
.blkb 64
fao_ctl:
.ascid "!AC!AC"
out_dsc:
.long out_len
out_adr:
.blkl 1

.align quad
sys_prv:
.quad <prv$m_sysprv!prv$m_audit> ; Just to test HO-LW
del_prv:
.quad 0
old_prv:
.blkq 1

persona_id:
.long 0
byte_cnt:
.long 10
vm_addr:
.blkl 1
msg_vec:
.long 1
.long ss$_abort

.psect _maher$scratch,pic,con,rel,lcl,noshr,noexe,rd,wrt,quad

scratch_lw:
.long 0

.psect _maher$code,pic,con,rel,lcl,shr,exe,rd,nowrt,quad

.sbttl Get directory info

define_service maher$get_user_dir,3

ifnord #8,@4(ap),99$ ; Can descriptor be read
movzwl @4(ap),r8 ; Get username len
bnequ 10$ ; Check length <> zero
movzwl #ss$_badparam,r0
ret

10$: cmpw #usrnam_max,r8 ; Check length <= 12
bgequ 20$
movzwl #ss$_badparam,r0
ret

20$: addl3 #dsc$a_pointer,4(ap),r7 ; Get -> to username ->
ifnord r8,(r7),99$ ; R access to username
string
ifnowrt #out_len,@8(ap),99$ ; W access to output buff
ifnowrt #2,@12(ap),99$ ; W access to output len
brb 100$

99$: movzwl #ss$_accvio,r0 ; Indicate access violation
ret

100$: $setprv_s -
enbflg=#enable,-
prvadr=sys_prv,-
prvprv=old_prv

$getuai_s -
contxt=uai_ctx,-
usrnam=@4(ap),-
itmlst=uai_lst
blbc r0, 999$

$persona_create_s - ;\
persona=scratch_lw,- ; \
usrnam=@4(ap) ; |
blbc r0, 999$ ; |
movl scratch_lw,persona_id ; > Just a couple
; > of dodgy tests
pushl #0 ; |
pushal vm_addr ; |
pushal byte_cnt ; /
calls #3,g^lib$get_vm ;/
blbc r0, 999$

movl 8(ap),out_adr ; Set descriptor address
$fao_s ctrstr=fao_ctl,-
outlen=@12(ap),-
outbuf=out_dsc,-
p1=#def_dev,-
p2=#def_dir

999$: movl r0,r5
evax_bic -
sys_prv,old_prv,del_prv ; Turn off privs before
exit!
$setprv_s -
enbflg=#disable,-
prvadr=del_prv
movl r5,r0
ret


exec_rundown: .jsb_entry ; Entry point for rundown
; handler

$putmsg_s - ; sys$examples:uwss.c says
no?
msgvec=msg_vec ; but Exec mode is ok

rsb


.PAGE
.SBTTL Privileged Library Vector

;+
; Any psect with the VEC attribute will be automatically moved to the start
; of the image.
;-
.psect dickie$services,page,vec,pic,nowrt,exe

.long plv$c_typ_cmod ; Set type of vector to change
; mode dispatcher
.long 0 ; Reserved
.long kernel_routine_count ; # of Kernel mode routines
.long exec_routine_count ; # of Executive mode routines
.address kernel_table ; Kernel routine list
.address exec_table ; Exec routine list
.long 0 ; Kernel rundown handler
.address exec_rundown ; Exec rundown handler
.long 0 ; RMS Dispatcher
.long 0 ; Kernel routine flags
.long 0 ; Exec routine flags

.end

$!
$ macro/list/enable=quad maher$share
$!
$ link /share=maher$share -
/sysexe -
/map -
/cross -
/full -
/notrace -
/section_binding -
maher$share, -
sys$input:/options

gsmatch=lequal,2,0

symbol_vector = (maher$get_user_dir=procedure)

protect=no
collect=scratch,_maher$scratch

protect=yes
collect=safe,_maher$data

$!
$copy/log maher$share.exe sys$common:[syslib]
$!
$if f$file_attributes("sys$share:maher$share.exe","KNOWN")
$then
$ installx replace sys$share:maher$share.exe
$else
$ installx add sys$share:maher$share.exe -
/open/header/share=address/protect
$!
$! If you have your GH_RSRVPGCNT SYSGEN parameter geared up for it,
$! you can install maher$share as /RESIDENT as in:
$!
$! installx add sys$share:maher$share.exe
$! /open/share=address/protect/resident
$endif
$!
$! Need SYSPRV to link against these services
$!
$set file/protection=(w:e) sys$share:maher$share.exe
$purge sys$share:maher$share.exe
$!
$create maher$user.cob
identification division.
program-id. ef_get_user_dir with ident "V2.0".
*
data division.
working-storage section.
01 ss$_normal pic 9(9) comp value external ss$_normal.
01 rms$_rnf pic 9(9) comp value external rms$_rnf.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 username_desc pic x(8).
*
01 out_dir.
03 out_dir_len pic 9(4) comp.
03 out_dir_text pic x(94).
*
procedure division
using out_dir,
username_desc.
00.
move spaces to out_dir_text.
move zeroes to out_dir_len.

call "maher$get_user_dir"
using username_desc, out_dir_text, out_dir_len
giving sys_status.
if sys_status = rms$_rnf
move "NL:" to out_dir_text
move 3 to out_dir_len
else
if sys_status not = ss$_normal
call "lib$stop" using by value sys_status.

exit program.
*
end program ef_get_user_dir.
$!
$cobol/lis maher$user.cob
$link/share=maher$user.exe maher$user.obj,sys$input/opt

sys$library:maher$share/share

symbol_vector=(ef_get_user_dir=procedure)

gsmatch=lequal,2,0
$!
$define/nolog maher$user 'f$parse("maher$user.exe")
$sql:==$sql$
$sql
attach 'file mf_personnel';

drop function ef_get_user_dir;

create function ef_get_user_dir (in char(32) by descriptor)
returns varchar(94) by reference
language sql
;
external name ef_get_user_dir
location 'maher$user' with all logical_name translation
language cobol
general parameter style variant
comment is 'Get UAF device and directory info for user'
BIND ON CLIENT SITE
bind scope connect
;
commit;
exit;
$exit
$!
$no_priv:
$ write sys$output -
"Insufficient privilege. You need (CMKRNL,SYSPRV,PFNMAP,BYPASS)"
$ exit 44
$no_vax:
$ write sys$output "This code only works on alpha"
$ exit 44

Mark Hemker <hem...@insightbb.com> wrote in message
news:5752ivskpr05bvsve...@4ax.com...

Richard Maher

unread,
Jul 26, 2003, 5:31:36 AM7/26/03
to
Hi,

> Everyone can use a UWSS, too.

Bullshit! Everyone can have Execute access to a UWSS but that's not much use
to a hacker without Read access. Unless they have Read access to it they can
only "use" the UWSS in the context of what the privileged designer of the
system intended. (For those that don't know you need Read access to LINK or
LIB$FIS against a UWSS shareable image)

Regards Richard Maher.

Hoff Hoffman <ho...@hp.nospam> wrote in message
news:s8dUa.890$cf5...@news.cpqcorp.net...

Mark Hemker

unread,
Jul 26, 2003, 7:41:44 AM7/26/03
to
On 25 Jul 2003 18:05:58 -0500, Kilg...@SpamCop.net (Larry Kilgallen)
wrote:

I'll definitely have to take a look at $ACM. Since we support our
application on older versions of VMS, I hadn't considered looking at
$ACM. At this point, I may need to consider requiring the users to
upgrade to the current version of VMS if they want this functionality.

>> Thanks for the help. I am also looking into using protected
>> subsystems, but we still run into an issue with the user being able to
>> run the program from DCL and gaining access to the protected
>> directory.
>>
>> Let me explain what the protected directory is used for:
>> -Copy a file from a public directory into the protected directory.
>> -Run a program that manipulates the file in the protected directory
>> and creates a new file.
>> -Delete the input file we just manipulated.
>> -Queue the resulting file to a print queue with /DELETE so that the
>> file is automatically deleted.
>>
>> We have a requirement that the files not be accessible to the user
>> except through our program and that is why we have all of the hoops to
>> jump through.
>
>"Protected Subsystems" is the specific nature of a particular VMS feature
>on both VAX and Alpha. It will allow you to do what you described there
>just fine, but it would seem you need to read and understand documentation
>related to protected subsystems.
>
>But what you describe there has nothing at all to do with validating a
>username and password. Do you really have two problems to solve ?

Your right, there are two different problems that are trying to be
solved. In my own confusion, I kept putting them into the same
program.

The first problem and most important at this point is handling the
protected directory. Let me give some more background and describe
the problem in more detail if I can. Our application creates a file
in a public directory. We then run a third-party application at a DCL
prompt that reads this file, merges the data with a template file,
adds some additional calculated data and then writes out the resulting
file which we then send to a printer. We need to be able to prevent
someone from modifying the original data file in the public directory
and running it through the third-party application and reprinting with
the new data. We also need to prevent someone from modifying the
resulting file and reprinting it.

I know this is ugly and I know the path I am currently following still
has some security holes, but I am trying to minimize the size of those
holes and the length of time that they exist.

The second problem is to implement an override functionality. There
are certain functions in my application that require a manager to
approve their use. Currently, they enter their username and password
that they use to log into my application. I would like for them to be
able to enter their VMS username and password to provide this
override. That is where the $GETUAI call comes in so that the
manager's login credentials can be validated from the user's context.

Mark

Larry Kilgallen

unread,
Jul 26, 2003, 8:43:17 AM7/26/03
to
In article <c0p4ivcsmap28uimr...@4ax.com>, Mark Hemker <hem...@insightbb.com> writes:
> On 25 Jul 2003 18:05:58 -0500, Kilg...@SpamCop.net (Larry Kilgallen)
> wrote:
>
>>In article <df640d0b.03072...@posting.google.com>, mhe...@remember.com (Mark Hemker) writes:

>>> I am trying to avoid creating any security holes and I just haven't
>>> had much luck finding a way of accomplishing my needed goal without
>>> creating one.
>>
>>$ACM was provided because of the difficulty of doing this.
>>
> I'll definitely have to take a look at $ACM. Since we support our
> application on older versions of VMS, I hadn't considered looking at
> $ACM. At this point, I may need to consider requiring the users to
> upgrade to the current version of VMS if they want this functionality.

If you can do that from a product management standpoint, it would be
_much_ better.

> Your right, there are two different problems that are trying to be
> solved. In my own confusion, I kept putting them into the same
> program.

There is nothing wrong with having them in the same program -- they
just need to be separated when describing the issues to those of us
in comp.os.vms :-)

> The first problem and most important at this point is handling the
> protected directory. Let me give some more background and describe
> the problem in more detail if I can. Our application creates a file
> in a public directory. We then run a third-party application at a DCL
> prompt that reads this file, merges the data with a template file,
> adds some additional calculated data and then writes out the resulting
> file which we then send to a printer. We need to be able to prevent
> someone from modifying the original data file in the public directory
> and running it through the third-party application and reprinting with
> the new data. We also need to prevent someone from modifying the
> resulting file and reprinting it.

That is the sort of thing for which Protected Subsystems were designed
(accessing data only with specific programs).

But why must this be a "public" directory ? Can't it be a directory
private to this application (as distinguished from this user).

The tough part is queueing a print job for data which the user can
temporarily access (via the Protected Subsystem) but cannot access
normally (when the job starts to print). Have you considered having
a background mechanism whose job is to "print everything in Directory X" ?
Or do the print jobs need to have the ownership of the individual user ?

> The second problem is to implement an override functionality. There
> are certain functions in my application that require a manager to
> approve their use. Currently, they enter their username and password
> that they use to log into my application. I would like for them to be
> able to enter their VMS username and password to provide this
> override. That is where the $GETUAI call comes in so that the
> manager's login credentials can be validated from the user's context.

So if I wanted to attack your $GETUAI design, I would sit there at the
override prompt, guessing the manager's password. Depending on the
nature of your managers, I might succeed, and you would not know it.

Of course you could try to implement something like VMS Breakin Evasion,
keeping me out and notifying you that attempts were being made. But
$ACM provides all of that, integrated into the normal VMS security
mechanisms. If you were to do it yourself you would have to write
some considerably privileged code, which is fraught with peril. It
seems better to me to depend on that which is built into VMS.

Saying your feature is only for those running on newer versions of
non-VAX VMS seems to me the wisest decision.

JF Mezei

unread,
Jul 26, 2003, 12:15:05 PM7/26/03
to
Richard Maher wrote:
> UWSSs are definitely the right way to go. (Exactly why Hoff continues to
> persue his Nanny-State/Ferenheit-451 agenda of banning people from using
> UWSSs and in particular the MACRO compiler is beyond me!

Hoff is well respected and his presence here is appreciated. So don't insult
him... (even if you have a point). The only insult you can make of Hoff is
when he has those catfights with Andrew :-)


> a couple of privileged shareables (eg: RDB$COSIP) and see *all* of the
> plethora of other RTLs that these images are linked against. So don't do as
> they do just do as they say? I don't think so. *SOME OF THESE LAND MINES
> EVEN CALL OUT to CRTL!!!* Let's all pray that it's not from inner-mode!)

It is my understanding that a user written system service does not necessarily
inherit all mighty privs, they must be enabled and disabled from within the
system service (making sure you disable the priv before returning to the
caller). If one were to change the mode back to user and disable privileges,
woudln't it then be safe for the user written system service to call out to
external routines ?

JF Mezei

unread,
Jul 26, 2003, 12:24:42 PM7/26/03
to
Mark Hemker wrote:
> The first problem and most important at this point is handling the
> protected directory.

This can be handled with protected subsystem and giving the directory the
right ACLs to allow that *image* to access the files.

Similarly, perhaps one of the VMS engineers can confirm this, but if your
application is a protected subsystem that auytomatically inherits the
"PAYCHECK" identifier, couldn't you then add an ACL to SYSUAF.DAT to grant
"PAYCHECK" the right to read the file ? Wouldn't $GETUAI then automatically
allow you to read any record in the SYSUAF without any special privileges ?

(Note that you would still have the responsability of making sure that
application option cannot be used to try combinations of passwords to
eventually find the right password. (Perhaps simply emailing a warning to an
application manager that user X has attempted more than Y times to guess the
password of user Z, and then exiting the application).

JF Mezei

unread,
Jul 26, 2003, 12:31:07 PM7/26/03
to
Larry Kilgallen wrote:
> some considerably privileged code, which is fraught with peril. It
> seems better to me to depend on that which is built into VMS.

Unless $ACM comes to VAX, you can't say it is built into VMS. You can say it
is built into Alpha-VMS.

Having the right version number for VMS is no longer an assurance of
compatibility since VAX VMS 7.2 is quite different and lacks a growing list of
features available on Alpha VMS 7.2

Mark Hemker

unread,
Jul 27, 2003, 7:39:29 AM7/27/03
to
On 26 Jul 2003 07:43:17 -0500, Kilg...@SpamCop.net (Larry Kilgallen)
wrote:

I don't think I have to use the "public" directory. I have considered
a background process that actually does the processing and decided not
to go that route for some reason. I will definitely have to revisit
that decision. I am going to look into creating a print symbiont also
to see if that would work.


>> The second problem is to implement an override functionality. There
>> are certain functions in my application that require a manager to
>> approve their use. Currently, they enter their username and password
>> that they use to log into my application. I would like for them to be
>> able to enter their VMS username and password to provide this
>> override. That is where the $GETUAI call comes in so that the
>> manager's login credentials can be validated from the user's context.
>
>So if I wanted to attack your $GETUAI design, I would sit there at the
>override prompt, guessing the manager's password. Depending on the
>nature of your managers, I might succeed, and you would not know it.
>

Yes, I know that is a security hole and it is one that I am not very
happy with.


>Of course you could try to implement something like VMS Breakin Evasion,
>keeping me out and notifying you that attempts were being made. But
>$ACM provides all of that, integrated into the normal VMS security
>mechanisms. If you were to do it yourself you would have to write
>some considerably privileged code, which is fraught with peril. It
>seems better to me to depend on that which is built into VMS.
>

I will look into $ACM some more since it sounds like it will handle
everything I need.


>Saying your feature is only for those running on newer versions of
>non-VAX VMS seems to me the wisest decision.

This is one of the ways that I have been able to force my clients to
upgrade their version of VMS in the past and it usually works pretty
well. The first time I did this was for Y2K support and then again if
they wanted the encryption capabilities of OpenSSL.

Thanks for everyones help. It looks like I have some more to look
into, but I definitely have some great pointers.

Mark

Hoff Hoffman

unread,
Jul 28, 2003, 5:19:08 PM7/28/03
to
In article <bftgv8$j8q$1...@sparta.btinternet.com>, "Richard Maher" <mahe...@hotspamnotmail.com> writes:

:UWSSs are definitely the right way to go. (Exactly why Hoff continues to


:persue his Nanny-State/Ferenheit-451 agenda of banning people from using
:UWSSs and in particular the MACRO compiler is beyond me! Certainly doesn't
:bode well for how these facilities will be implemented on Itanium :-()

Eh? I would simply prefer to use the least hazardous and least-privileged
approach, lest I open a security hole or encourage someone to open a hole.
Assigning privileges is something I have learned to handle with great care,
given unintended accesses and unintended consequences that can result. If
I can reasonably solve a task with a subsystem identifier, I'd clearly not
want to create and install an application with enhanced privileges.

This is not to say that UWSS operations are not useful and should not be
used -- solely to indicate that the best tool for the job should be used.
Other tools that can provide or replace a UWSS can include a pseudo-device
driver -- for kernel-mode operations at low IPL, the pseudo-device driver
can provide useful capabilities and an API for users. And privileged
server processes and network communications are another approach.

:Simply drop the /PROTECT and /NOSYSSHR qualifiers on your $LINK and you now


:have the ability to call whatever RTL you like. I believe it's
:SECURESHRP.EXE if you want $GETUAI. That's the easy part. You are now at
:your most vulnerable!!! It is up to you to protect your working-storage and
:I/O channels and everything else from outer-mode corruption and
:exploitation. (See the COLLECT and PROTECT linker options bellow)

When assigning privileges via UWSS, the usual result is to exit from
the inner-mode code, and this leaves the system wide open -- if you
stay in an inner-mode environment, you are also restricted on which
RTL functions you can call. (eg: None.) You can call most system
services from inner-mode (and non-elevated IPL) code, though some of
the services can and do have mode-related calling restrictions.

As I tell folks, you must always expect any of your APIs to be probed.
APIs that provide doorways to privileged-mode or privileged operations
or communications with privileged processes are obvious targets for
this probing, of course. This is less paranoia than it is pragmatism.

:So now you've made sure that your memory is protected from a dodgy or


:mallicious user-mode pointers and all *your* channels are $ASSIGNed and
:$QIOed at EXEC mode but how can you vouch for $getuai or other RTL routine?
:How can you trust them to do the right thing? What if a hacker is writing
:$QIOs to a random channel selector seeing if he gets a result 'cos PRIVs
:were used to access SYSUAF but the channel was mistakenly open in USER mode?
:What if *they* forget to protect their memory?

..

While a programmer has a comparatively small window with the design and
implementation and testing of security within an application, a system
cracker can spend an unlimited amount of time and effort probing the
resulting design. As such, I tend to be paranoid -- I've certainly seen
kernel-mode code hacked, and I've seen enough folks spending non-trivial
efforts in the attempt.

Put another way, I'd first prefer to secure my privileged code behind a
process-level security "wall". Sharing privileged and trusted code and
unprivileged and untrusted code within the same process is, well, an
interesting task -- mixed-trust environments are not trivial to code
correctly. Within the UWSS, the device driver, and OpenVMS operating
system environments, the programmer writing the privileged-mode code
has to secure it behind the mode-related page protections -- and as
Richard correctly comments, anything that is shared cannot be trusted.

Again, given my preferences and my experience, I tend to prefer the
biggest and most solid protective wall I can get between the privileged
code and the untrusted user code. The UWSS takes a little finesse and
some experience to get right, and can create a huge hole if done wrong.

..
:Anyway please search through the COV archives (search for blade guard) for


:other fruitless discussions on this subject. I have asked for guidence on
:dropping /PROTECT (but still being secure) hundreds of bloody times without
:any joy. I even dragged myself across North London to a "Hints and Kinks"
:session that supposed to discuss this stuff but the room was packed with
:System Managers and not Developers and tha air-conditioning was off so you
:know what a hoot that was :-)

I've a prototype presentation session on writing secure code that I've
presented to an internal audience, it's certainly well beyond the Hints
and Kinks session I present.

:I'm also about to post another UWSS example that let's an unprivileged user


:wait until a file is created in a directory!

We've had a few applications that have insinuated themselves into the
file locking that have busted over OpenVMS releases -- we (OpenVMS) do
need to implement an API for this capability at some point, though this
task is possible now using security alarms and the security-related
mechanisms. The resulting code is ugly, of course, but is possible
using only the supported interfaces.

:(Did you know that any user can do a $dir/fid on any file. I thought telling


:you whether or not a file exists (if you don't have priv) was wrong? See, my
:RTL with tell you the filename that I'm waiting for but if (when it gets
:created) you don't have priv to see it then your AST will fire and give you
:SS$_NOPRIV in the IOSB. But that sought of defeats the purpose don't you
:think?)

The filename itself is not in a protected namespace -- this is something
that the folks interested in NCSC-style system security reference in the
NCSC "rainbow" books. The file contents are protected. But if a file
should be named TheSuperSecretCodeWordIsFooBar.Txt, well...

JF Mezei

unread,
Jul 28, 2003, 7:54:47 PM7/28/03
to
Hoff Hoffman wrote:
> I've a prototype presentation session on writing secure code that I've
> presented to an internal audience, it's certainly well beyond the Hints
> and Kinks session I present.

Sounds like the perfect topic for a presentation in Sue's november VMS conference.

0 new messages