[comp.sys.hp] How can I give users root-like privs. w/o the passwd ?

greg@cityzoo.acs.umbc.edu (Greg Sylvain,Lib 007,3929,4376834) (12/20/89)

From: greg@cityzoo.acs.umbc.edu (Greg Sylvain,Lib 007,3929,4376834)
Path: cityzoo.acs.umbc.edu!greg
Newsgroups: comp.sys.hp
Subject: How can I give users root-like privs, w/o the passwd ?
Expires: 
References: 
Sender: 
Reply-To: greg@umbc3.umbc.edu (Greg Sylvain,Lib 007,3929,4376834)
Followup-To: 
Distribution: world
Organization: University of Maryland, Baltimore County
Keywords: super-user

	Hi,

	I've run into a bit of a snag, I'm sure other people have had to do 
this, so here it goes.  I would like to give some specific users root-like
privs. to execute some privaledge commands.  But,  I don't want to give
them the root passwd, I think that's too much.  I specifically want to
give a user privaledge to mount a fs, and to halt (shutdown) the system in the
event of an emergency.  I tried setting up a newgrp for these users, and 
cvhanging the mod and group of the respective files.  But it didn't work, ( or
I may have missed a file) ?  Any suggestions ?


	Also, on an unrelated topic, I have a user that wants to boot a SUN386i
from his HP workstation.  (Using the HP as the server).  Do you think this can
be done, I din't think so, but I thought I'd give it a whirle.  (He wants to
use a HP9000s300 model 370, running HP-UX 6.5 for the cluster server, and the 
SUN386i as a cnode)



				Thanks
					Greg


				Greg Sylvain
				Academic Computing Services
				Systems Programmer
			
	UUCP:           	...{uunet}!umbc3!greg
	Internet (Arpa) :	greg@umbc3.umbc.edu
 	BITNET :		GREGS@UMBC

djw@hpldsla.HP.COM (12/22/89)

> I've run into a bit of a snag, I'm sure other people have had to do 
> this, so here it goes.  I would like to give some specific users root-like
> privs. to execute some privaledge commands.  

As  a  general   comment,   you  might   like  to  look  at  the
setprivgrp(1,2,3?)  man pages.  I don't think they will work for
you in this case, but it's nice to be aware of the mechanism.

>  ................................................I specifically want to
> give a user privaledge to mount a fs, and to halt (shutdown) the system in the
> event of an emergency.

A technique I used to use as a sys-admin  is as follows.  Create
the command(s) you want the user to be able to use.  Ensure that
they  will do  nothing  more than what you wish to allow.  Setup
the command with the set user id bit set (see  chmod(1,2)),  and
file owner of root.  This will mean the command gets executed as
root, not as the user who invoked it.  This should do the trick.
BUT be careful the command do only what you want to allow.

An even better  extension to this  technique, is for the command
to check in some  (writeable  by root *only*) file for a list of
valid users or groups.  The 'special' command should ensure that
the login user id (found in $LOGIN) is one of the users  listed.
That allows you to control access to the command.

Here is a quick example that uses a shell script.

#!/bin/sh
#
#	sysstop.sh - shutdown the system.
#
PATH=/bin; export PATH	# VERY important.
if grep "$LOGNAME" /usr/adm/shutdown.list > /dev/null 2>&1
then
	cd /
	exec /etc/shutdown
else
	echo "permission denied" >&2
	exit 2
fi

--------

Set up the command as follows:

chown root sysstop
chmod 4555 sysstop

chown root /usr/adm/shutdown.list
chmod -w /usr/adm/shutdown.list

By adding  user names to the  shutdown.list  file, you add users
allowed to run the program.

Note that setting the PATH is super  important in a shell script
run as root.  If you  don't do this,  the user can  place  their
'special'  grep  command  (the one that adds a new root login to
/etc/passwd)  in the PATH before  running  sysstop and use it to
comprimise  security.  Set the PATH up front or explicitly  call
the command you wish to use (ie,  "/bin/grep"  not "grep").  The
latter can get a bit ugly in long scripts.

You can use the same  technique  for  creating a limited  access
root  powerful C programs  also - in fact this is probably  more
common.

Hope that helps,

djw@hpldsla

#include	<disclaimer>
it probably doesn't work
nobody is going to support it
use at your own risk
I'm not working for HP at this moment
I haven't had flu shots lately.

tomg@hpcvlx.cv.hp.com (Thomas J. Gilg) (12/22/89)

> ......................  I would like to give some specific users root-like
> privs. to execute some privaledge commands.  ...........................

Are you trying "set user ID" or "set group ID".

Example:  you cannot as a normal user modify /etc/passwd, therefore,
the command /bin/passwd has the permissions:

-r-sr-xr-x   1 root     bin       112640 Oct 12 00:00 /bin/passwd

  % chown root file
  % chgrp bin  file
  % chown 4555 file

This allows a normal person to run a script/binary as though he was
super-user.  There may be corner cases on this though.

Thomas Gilg
tomg@cv.hp.com

wayne@dsndata.uucp (Wayne Schlitt) (12/25/89)

In article <3140011@hpldsla.HP.COM> djw@hpldsla.HP.COM writes:
> 
> Here is a quick example that uses a shell script.
> 
> #!/bin/sh
> #
> #	sysstop.sh - shutdown the system.
> #
> PATH=/bin; export PATH	# VERY important.

it is also _very_ important to set the IFS variable to space, tab and
newline via:

IFS=" \t\n"; export IFS

for those who havent used the IFS variable much ( :-> ), it is the
"internal field separator", and it is what the shell uses to separate
words.  as an example, if the IFS was set to "r", then the following
command would have been parsed as the command "if g" and the option
"ep $LOGNAME /usr/adm ...".  there are a lot of times that the bad
guys can use this to break security.


> if grep "$LOGNAME" /usr/adm/shutdown.list > /dev/null 2>&1

using $LOGNAME for anything important is a very bad thing to do.
anyone can set it to be anything they want.  it is my understanding
that using the command whoami isnt much better because it can be
tricked into using the $LOGNAME variable to tell you who you are.

> then
> 	cd /
> 	exec /etc/shutdown
> else
> 	echo "permission denied" >&2
> 	exit 2
> fi
> 


although i am not aware of all of the holes, from what i know, setuid
shell scripts are usually a major no-no.  the major problem with
setuid shell scripts are:

1) any one who can execute them can read them.  this gives the bad
   guys lots of information on how to break them.  if you use a
   compiled C program, you can take off the read permission and the
   bad guys have a lot less to go on.

2) if you are writing in C, you can change your effective userid back
   to something "safe" after you have opened the files you need.  you
   cant set your userid in a shell script

3) /bin/sh (the program that runs your shell scripts) is a fairly
   large and complicated program.  this leaves lots of subtle things
   that the bad guys can use to break your scripts.  as an example, i
   believe on some systems, if you invoke the shell script via a C
   program with the "exec" command and add a minus sign to the
   beginning of the shell script name, it will always execute the
   users .profile.  and since the bad guys can usually write to their
   .profiles, they can do anything they want...

unix isnt very good about being able to give away just some of roots
privileges.  in many ways it is better to just give in and trust a few
people with the root password.  they will tend to be more careful with
it's power and they will feel like they are responsible for what
happens.  of course, this has left the realm of computer security and
gone to into the realm of human nature and everyone is different, but
in either case, you are going to have to watch the system carefully.

-wayne

frank@hpwrce.HP.COM (Frank Stutzman) (12/27/89)

...
> 	Also, on an unrelated topic, I have a user that wants to boot a SUN386i
> from his HP workstation.  (Using the HP as the server).  Do you think this can
> be done, I din't think so, but I thought I'd give it a whirle.  (He wants to
> use a HP9000s300 model 370, running HP-UX 6.5 for the cluster server, and the 
> SUN386i as a cnode)

Since everyone else has addressed your priviliges question, I'll answer this 
one.

In short, there's not a wisper of a chance of booting your 386i off of the 
9000.

HP and Sun use radically different diskless schemes.  The 300s that can boot
diskless (virtually every model) have a special bootrom that interrogates the
network with a broadcast that is (as I understand it) unique to HP.  In order
to boot the sun off of the HP you would have to have one of thes roms in the 
sun.  Its not very likely you would be able to wedge one in.


|=============================================================================|
|Frank Stutzman                            | "What is wanted is not the will  |
|Hewlett-Packard Western Response Center   |  to believe, but the will to     |
|Mtn. View, Ca                             |  find out, which is the exact    |
|frank@hpwrc.hp.com                        |  opposite." -Bertrand Russell    |
|=============================================================================|

human@hpindda.HP.COM (Aaron Schuman) (12/27/89)

Frank>	In short, there's not a whisper of a chance of
Frank>	booting your 386i off of the 9000.

Frank>	to boot the Sun off of the HP you would have to
Frank>	have one of these ROMs in the Sun.

Frank>	It's not very likely you would be able to wedge one in.


No, you can't wedge one in, but would you have to?
Frank assumes that you'd boot with the HP protocol,
but couldn't you boot with the Sun protocol?  You'd
need to port Sun's boot protocol from a Sun server
to an HP9000 (a simple matter of software :-).

I don't know anybody who has ever done this port.
I don't know whether it would be easy or hard.
If you try it and you have problems, I can imagine
what they'd say to you at the Western Regional
Response Center.  Something like "You did WHAT?"

walasek@hpcc01.HP.COM (Arthur Walasek) (12/27/89)

One thing on setting root access on some files is that you have to be
very careful that these programs don't access common user writable files
and that they don't contain any shell escapes.  We had a large problem
with a special mailer that would put you in vi to edit the file you 
wanted to send, then the person would shell-escape from vi and --- hey
wow, I'm root.  The sad part about it was that the most trouble was 
done by a novice user who didn't know what he/she was doing and did
something like rm -r /usr0/<name>/.* (which also rm -r'd ..)....

Just a warning...

Arthur.

montnaro@spyder.crd.ge.com (Skip Montanaro) (12/27/89)

This topic is certainly of wider interest than to just HP folks. Be that as
it may, you might be interested in Tom Christiansen's paper in the USENIX
LISA III workshop entitled "Op: A Flexible Tool for Restricted Superuser
Access". You can probably get Tom (tchrist@convex.com) to send you a
reprint. The man page for op(8), taken from our Convex, appears below. Don't
ask me how you're going to get op(8) running on your HP. Perhaps you can
convince HP to include it in HPUX 10.5 :-).

------------------------------------------------------------------------------

NAME
     op - operator interface tool for giving restricted access to
     privileged commands

SYNOPSIS
     /etc/op mnemonic [ arg ... ]
     /etc/op -h [ -u username ] [ mnemonic ]

DESCRIPTION
     The op tool provides a flexible means for system administra-
     tors to grant to any set of trusted users permission, or
     access, to execute certain root operations without having to
     give them full superuser privileges.  It is a non-
     interactive command interpreter that places restrictions on
     which users are allowed to execute which privileged com-
     mands.

     The functions (or mnemonics) understood by the op program
     are listed in the configurable data file /etc/op.access,
     along with the meaning of each mnemonic (an exact UNIX com-
     mand that will accomplish the desired result) and who is
     allowed to execute it.  The restrictions can be made as
     tight as each site demands, as determined by the system
     administrator who customizes the op.access file.

     The format of the access database file is fully described in
     op.access(5).  In summary, it contains a mapping of mnemon-
     ics, or operator functions, to the full pathnames of pro-
     grams that should be invoked and the arguments that are
     allowed, if any.  The arguments to the executed program can
     be a combination of literal and variable arguments, and res-
     trictions can be placed on which values are valid substitu-
     tions for the variable arguments.  The args given on the op
     command line are only necessary to specify any variable
     arguments the mnemonic may need.  While the superuser does
     not have access permissions checked (root can run anything),
     each arg's validity is verified.

     The following set of attributes can also be controlled for
     each mnemonic by the op program:

     o the uid to set (root by default)
     o the gid to set (not changed, by default)
     o the directory to chdir(2) to (not changed, by default)
     o the root directory to set with chroot(2) (not changed, by
     default)
     o the umask to set (022 by default)
     o a list of groups allowed to execute this function (none by
     default)
     o a list of users allowed to execute this function (none by
     default, except the superuser)
     o the range of valid arguments for the command (any value

     per variable argument by default)
     o any number of environment variable settings (none by
     default).

     The following options are recognized:

     -h [ mnemonic ]
          This option requests help and informs the operator of
          the commands he or she is allowed to run and how they
          are to be run.  The operator is not allowed to view the
          access file directly for security reasons.  Without an
          argument, this option will display a list of mnemonics
          which the invoking user is allowed to execute.  If a
          specific mnemonic is given, and if that mnemonic is
          defined in the access file and the user has permission
          to execute it, then a "usage" message is output,
          describing the valid arguments accepted by that
          mnemonic and the order in which they should be given
          (if there are any variable arguments to that mnemonic
          at all).

     -u username
          Use the specified username when checking for permission
          to execute the mnemonics listed in the /etc/op.access
          file.  This option may only be used by the superuser
          and in conjunction with the -h option.

     If the -h flag (for help) is not given, the op program veri-
     fies that the invoking user is allowed to run a particular
     command, validates any variable arguments, and properly sets
     up any of the above-specified attributes before executing
     the associated program.  Security measures such as clearing
     out the vector of group permissions and clearing all but the
     specified environment variables are taken before the command
     is executed.

     Attempted executions of op (whether successful or not) are
     logged via syslog(3).  The information logged includes when
     and by whom op was executed and with which command-line
     arguments.  Invalid users or variables are especially noted.
     Many messages written to the log file contain the user's
     login name, which will be contained within square brackets
     ([]).

     All op logging is done using syslog's LOG_AUTH facility.
     The usage information will be logged with a syslog level of
     LOG_INFO, usage errors (such as invalid or wrong number of
     arguments) use the LOG_NOTICE level, an unauthorized user
     will be noted with the LOG_WARNING level, and a failed
     execve of the command will be logged with the LOG_ERR level.
     The log files to which this syslog information is written
     can be customized within the /etc/syslog.conf file; see

     syslogd(8) for information on how to configure this file.

EXAMPLES
     The following line in the op.access file gives the user
     bruce and any member of the opers group permission to run
     weekly dumps on any of the named file systems by simply typ-
     ing op weekly valid_filesys_name, where valid_filesys_name
     is one of /, /usr, or /mnt.  Because no other attributes are
     defined for this mnemonic, the defaults are used: the dump
     program runs as root, but the gid, current working direc-
     tory, and root directory remain unchanged.  The umask is
     022, and the group and environment vectors are cleared.

           weekly   /etc/dump 0Gun $1;  users=bruce groups=opers
                                   $1=/,/usr,/mnt

     For more examples of the access file format and usage, see
     the op.access(5) manual page.

FILES
     /usr/etc/op.access   list of operator mnemonics and restric-
     tions enforced by op

SEE ALSO
     op.access(5), syslog(3), "Operator Interface" chapter in the
     CONVEX System Manager's Guide

WARNINGS
     It is up to each individual system administrator to assure
     that the programs listed within the op.access file are
     secure.  It is recommended that the access file not contain
     shell scripts that run as root.  Also, caution should be
     taken in including any interactive programs in the access
     database.

------------------------------------------------------------------------------

--
Skip (montanaro@crdgw1.ge.com)

ken@hpubrcf.HP.COM (Ken Green) (12/29/89)

> 3) /bin/sh (the program that runs your shell scripts) is a fairly
>    large and complicated program.  this leaves lots of subtle things
>    that the bad guys can use to break your scripts.  as an example, i
>    believe on some systems, if you invoke the shell script via a C
>    program with the "exec" command and add a minus sign to the
>    beginning of the shell script name, it will always execute the
>    users .profile.  and since the bad guys can usually write to their
>    .profiles, they can do anything they want...
> 

	You don't even need to go to the trouble of writing a C program, There
are much simpler ways to get any shell script to execute your .profile.

	Please don't write any set UID root own shell scripts if you want to
have any security on your system. If doesn't take much to write the code in C
and avoid all the secuirty holes.

rer@hpfcdc.HP.COM (Rob Robason) (12/30/89)

> > Also, on an unrelated topic, I have a user that wants to boot a SUN386i
> > from his HP workstation.  (Using the HP as the server).  Do you think
> > this can be done, I din't think so, but I thought I'd give it a whirle.
> > (He wants to use a HP9000s300 model 370, running HP-UX 6.5 for the
> > cluster server, and the SUN386i as a cnode)

> In short, there's not a wisper of a chance of booting your 386i off of the 
> 9000.

Well, there is one way, but it's not using HP-UX.  MtXinu has a BSD 4.3
product that has NFS 4.0 and runs on the 300.  My understanding is that
it can act as a diskless server or client with Sun Systems.  You would
be giving up actual HP-UX and the support that HP provides.  You can get
more info from Mt Xinu in Berkeley, CA.

Rob Robason
Hewlett-Packard Company, HP-UX Lab
3404 East Harmony Road M/S 99
Fort Collins, Colorado 80524
----------------------
Electronic Mail:
Internet: rer@hpfclg.HP.COM
UUCP: (hplabs!)hpfcla!rer
HPDESK: ROB ROBASON/HP4000/UX (rob_robason%ux@hp4000)
----------------------
Public Statement Disclaimer:
Opinions expressed in public forums such as comp.sys.hp, and in private
correspondence with persons outside of HP, are my own, do not represent
HP policy and are not to be construed as any sort of commitment on the
part of HP.

larryc@hpislx.HP.COM (Larry Corsa) (01/03/90)

> 	I've run into a bit of a snag, I'm sure other people have had to do 
> this, so here it goes.  I would like to give some specific users root-like
> privs. to execute some privaledge commands.  But,  I don't want to give
> them the root passwd, I think that's too much.  I specifically want to
> give a user privaledge to mount a fs, and to halt (shutdown) the system in the
> event of an emergency.  I tried setting up a newgrp for these users, and 
> cvhanging the mod and group of the respective files.  But it didn't work, ( or
> I may have missed a file) ?  Any suggestions ?
> 

At the  risk of  disseminating  info I only  barely  understand,  I have
attached  source  to a  program  called  uid_chng  , which  takes as its
argument a command which is to be executed with root permission.  It has
an access  file which  allows it to be  discriminating  in its choice of
user and command access.  I freely admit that its presence on any system
is a likely security breach.  ( I also admit to using it.  :-) )

The source is reasonably self-documenting (which is to say I didn't get
any documentation when I received it either!).

Let it also be known that this is UNSUPPORTED by either myself or my
employer!

Regards,

Larry Corsa                             |  HPDesk address: HP0900/UX
MSO Technical Product Support Engineer  |  HPUX address: larryc@hpisla
Measurement Systems Operation           |  (303) or TELNET 679-5080 
815 14th Street SW                      |  FAX (303) or TELNET 679-5957
Mail Stop CU312                         |
Loveland, CO 80537, USA                 |


================== cut here ===========================

/*******************************************************************************PROGRAM    uid_chng.c
PURPOSE    Assume super user priveliges and execute a program
********************************************************************************
FUNCTIONAL DESCRIPTION
Sets the process's user ID to 0 and exec's the passed shell program.

NOTES
Compile with:
	cc -n -O -o uid_chng uid_chng.c
	cc -n -O -DDEBUG -o uid_chng uid_chng.c # see what will be executed

This program must be owned by root with suid bit set.
	chown root uid_chng
	chgrp other uid_chng
	chmod 4111 uid_chng
******************************************************************************/
#include <stdio.h>
#include <string.h>

char  sccs_id[] = "@(#)  uid_chng.c, version 1.9, dated 2/13/86";

/***************************************************************************************                                                                ********
*******                   main program                                   *******
********                                                                ********
*******************************************************************************/

#define MAXCMD 256               /*  maximum allowed length of command */
#define YES 1
#define NO 0

#define ROOT 0                   /* super user ID */

extern int errno;
char *getenv();

void main(argc,argv)
int    argc;
char **argv;

{
       unsigned short getuid();       /* returns user id */
       /*
       |     local data
       */
       int i;
       char full_command[MAXCMD];   /* place for the command */
       char user_shell[100];        /* $SHELL from environment */

       /*
       | Must have at least one argument.  Do this now so we don't try
       | and look for nothing in the ACCESS_FILE.
       */
       if ( argc <= 1) {
	  fprintf(stderr,"%s: No command given. \n", argv[0]);
	  exit(1);
	  }

       /*
       | if root is calling, then we need not verify priviliges nor 
       | do we have to setuid().
       */
       if ( getuid() != ROOT )  {
	       /*
	       | make sure the user is allowed to call the requested command
	       */
	       if ( idcmdok ( argv[1] ) != YES ) {
		  fprintf(stderr,"%s: Invalid user and/or command.\n",argv[1]);
		  exit(1);
		  }
	       
	       /*
	       | become super user
	       */
#ifndef DEBUG
	       if ( setuid(ROOT) == -1 ) {
		  fprintf(stderr,
			  "%s: The uid_chng command must be priviliged.\n",
			  argv[0]);
		  exit(1);
		  }
#else
	       /*
	       | debug is ON, just show message rather than setting uid
	       */
	       fprintf(stderr,"Becoming super user\n");
#endif
       /*
       |end of "if not root"
       */
       }

       /*
       | make the command
       */

       strcpy(user_shell, getenv("SHELL="));
       strcpy(full_command, " ");
       if (strcmp(user_shell,"/bin/sh")  == 0 || 
           strcmp(user_shell,"/bin/ksh") == 0 || 
           strcmp(user_shell,"/bin/csh") == 0 ) {
	        strcpy (full_command, user_shell);
	        strcat (full_command, " -c \"");
	  }
       strcat (full_command, argv[1]);    /* command name */
       
       /*
       | tack on arguments to the command
       */
       for (i=2; i <= argc; i++)  {
	     strcat (full_command, " ");   /* put in spaces... */
	     strcat (full_command, argv[i]);
	     }
       
       strcat (full_command, "\"");
#ifndef DEBUG
       /*
       | execute the command with its arguments
       */
       if (system(full_command) != 0)  {
	   fprintf(stderr,
                   "\n%s: System(2) error #%d\n", argv[0], errno);
	   exit(1);
	   }
#else
       /*
       | print the argument and quit
       */
       printf("\n%s\n",full_command);
#endif
/*
| end of main program
*/
}



/***************************************************************************************                                                                ********
*******                    idcmdok()                                     *******
********                                                                ********
********************************************************************************

idcmdok - id command ok

This routine looks in the file ACCESS_FILE for the login user id.
If found, the corresponding line is searched for the requested command.
The format of the ACCESS_FILE is 
     "user_id:command,command,....."
     "user_id:*"
     "*:command,command,..."
    where command is a valid allowable command.  The "*" for command means
this user has no restricted command.  The "*" for user_id means the listed
commands can be executed by any user.  Also, tabs and spaces can be used to
separate files to enhance readability (at the expense of security). (?)

A user may be listed more than once.

If the line starts with a # sign, that line is ignored (for comments).

	  RETURNS:        YES if command ok
			  NO if command not allowed.

	  BUGS:           Note that /bin/rm is not the same as rm.
			  If the system administrator entered "rm"
			  in the ACCESS_FILE for a user to use, a clever
			  user looking for trouble could make his own 
			  version of "rm" (say a shell script) and if 
			  path points to the new rm before /bin/rm then 
			  the user's rm would execute with root privileges!

			  Therefore, ACCESS_FILE entries should have their 
			  entire pathname specified!!!

******************************************************************************/


#define ACCESS_FILE "/etc/su_access"
#define MAXLINE 256      /* max length of ACCESS_FILE entry */

int idcmdok(cmdpt)
char *cmdpt;       /* points to routine that wants to be executed */
{
	/*
	| local data
	*/
	FILE     *fp;     /* file pointer for ACCESS_FILE */
	FILE     *fopen();
	char     *token;  /* points to found token */
	static char id_token[] = "  :\n";  /* valid user_id delimiter */
	static char cmd_token[] = " 	,\n"; /* valid command delim */
	char login_name[15];
	char access_line[MAXLINE];

	/*
	| prepare access file
	*/
	if ( (fp = fopen(ACCESS_FILE,"r") ) == NULL )  {
		fprintf(stderr,"error: Can't open access file '%s'.\n",
			       ACCESS_FILE);
		exit(1);
		}
	/*
	| get the user's login id (name)
	*/
	if ( cuserid(login_name) == NULL )  {
		fprintf(stderr,"error: Can't get login name.\n");
		exit(1);
		}
	/*
	|  go through access file looking for the login name or a "*".
	|  If found, parse the line to find the requested command.
	|      If found, return YES; else, continue search until the
	|      access file is exhausted.
	|  Return NO if the proper match cannot be made.
	*/

	/* get a line */
	while ( fgets(access_line,MAXLINE,fp) != NULL )  {

            /* look for comment line*/
	    if (access_line[0] == '#' )  continue; 

	    /* check for empty line */
	    if ( (token = strtok(access_line,id_token)) == (char*)0 )  continue;

	    /* is the token found the login name or "*"? */
	    if ( strcmp(token,login_name) && strcmp(token,"*") ) continue;

	    /* user id matches... now look for command match */
	    while ( (token = strtok((char*)NULL, cmd_token)) != (char*)NULL )                    {
		 /* if there is white space after the userid then
		 |  the next strok() will send us the ":" separator, which
		 |  we don't want.  To address this case,
		 */
		 if ( token[0] == ':') strcpy(token, &token[1]);

		 /*  if there is also whitespace after the ":" then the
		 |   above fix would allow a null command, which we also
		 |   don't want.
		 */
		 if (token[0] == '\000') continue;

		 if ((strcmp(token, cmdpt) == 0) || (strcmp(token,"*") == 0))
		    return (YES);
		 }
	    }
	    /*
	    | proper match could not be made
	    */
	    return (NO);
/******************************************************************************/
}