/*****************************************************************************
/*
                                   CLI.c

Module to process (interpret) the HTTPD command line.  Allows images activated
by a "foreign verb" to behave in a way that approximates the CLI$ (Command
Line Interpreter) utility calls.


VERSION HISTORY
---------------
15-APR-2004  MGD  /LOCK obsolete
19-JUL-2003  MGD  add /[NO]NETWORK
03-MAY-2003  MGD  add /SYSUAF=VMS keyword
30-JAN-2003  MGD  add /PROFILE=NORULE keyword
23-SEP-2002  MGD  add /SCRIPT=AS=
16-SEP-2002  MGD  add /PERSONA[=RELAXED|AUTHORIZED|RELAXED=AUTHORIZED],
                      rework qualifier keyword parsing
05-MAY-2002  MGD  add /DEMO catch-all for freeware demo use, etc.,
                      /GBLSEC=NOPERM for no permanent global section
29-SEP-2001  MGD  add /[NO]INSTANCE[=integer] number of per-node instances,
                      /CLUSTER[=integer] grouping (changed from [=resname])
20-MAY-2001  MGD  add /GBLSEC=DELETE=<integer>
23-FEB-2001  MGD  add /SYSUAF=PROXY
20-DEC-2000  MGD  add /PROXY=
02-OCT-2000  MGD  add /DETACH, /IDENT=, /PERSONA=, /USER=
18-JUN-2000  MGD  add /ALL[=resname]
02-JAN-2000  MGD  add /[NO]ODS5, ability to use HTTPD$PARAM
30-OCT-1999  MGD  add /SYSPRV
29-SEP-1999  MGD  change /SYSUAF= ALL to RELAXED (backward-compatible)
30-JUL-1999  MGD  bugfix; /SYSUAF does not need a parameter!
26-MAY-1999  MGD  /SSL= now takes a string parameter
24-FEB-1998  MGD  /AUTH=ALL, /AUTH=(SSL,ALL), /SYSUAF=WASD_ID
07-NOV-1998  MGD  /[NO]WATCH=
07-AUG-1998  MGD  /PROMISCUOUS[=password]
06-JUL-1998  MGD  v5.1, /SYSUAF=ID
11-MAR-1998  MGD  /SYSUAF=(SSL,ALL)
04-FEB-1998  MGD  v5.0, /SSL, /SYSUAF=SSL
11-OCT-1997  MGD  v4.5, /CACHE, /VERSION
06-SEP-1997  MGD  v4.4, /FORMAT, /PROFILE, /SYSUAF, /SOFTWAREID
01-FEB-1997  MGD  HTTPd version 4
01-DEC-1995  MGD  HTTPd version 3
20-DEC-1994  MGD  multi-threaded daemon
20-JUN-1994  MGD  single-threaded daemon
*/
/*****************************************************************************/

#ifdef WASD_VMS_V6
#undef _VMS_V6_SOURCE
#define _VMS_V6_SOURCE
#undef __VMS_VER
#define __VMS_VER 60000000
#undef __CRTL_VER
#define __CRTL_VER 60000000
#endif

/* standard C header files */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

/* VMS header files */
#include <descrip.h>
#include <stsdef.h>
#include <ssdef.h>
#include <stsdef.h>

#include "wasd.h"

#define WASD_MODULE "CLI"

/******************/
/* global storage */
/******************/

BOOL  CliCacheDisabled,
      CliCacheEnabled,
      CliDemo,
      CliDetach,
      CliGblSecDelete,
      CliGblSecNoPerm,
      CliInstanceNoCrePrc,
      CliLoggingDisabled,
      CliLoggingEnabled,
      CliMonitorDisabled,
      CliMonitorEnabled,
      CliNetworkMode,
      CliNoNetworkMode,
      CliOdsExtendedDisabled,
      CliOdsExtendedEnabled,
      CliPersonaAuthorized,
      CliPersonaEnabled,
      CliPersonaRelaxed,
      CliPersonaRelaxedAuthorized,
      CliTests,
      CliVersion;

int  CliInstanceMax,
     CliServerPort;

char  CommandLine [256],
      CliParameter [256],
      CliProcessIdentName [64],
      CliProxyMaint [128],
      CliServices [256],
      CliScriptAs [64],
      CliUserName [64];

char  *CliAcceptHostsPtr = NULL,
      *CliRejectHostsPtr = NULL;

/********************/
/* external storage */
/********************/

#ifdef DBUG
extern BOOL Debug;
#else
#define Debug 0 
#endif

extern BOOL  AccountingZeroOnStartup,
             AuthPromiscuous,
             AuthPolicyAuthorizedOnly,
             AuthPolicySslOnly,
             AuthPolicySysUafProxy,
             AuthPolicySysUafSslOnly,
             AuthPolicySysUafRelaxed,
             AuthPolicySysUafIdentifiers,
             AuthPolicySysUafVms,
             AuthPolicySysUafWasdIdentifiers,
             AuthSysUafEnabled,
             AuthSysUafPromiscuous,
             AuthVmsUserProfileNoRule,
             AuthVmsUserProfileEnabled,
             ControlDoAllHttpd,
             LoggingFormatCombined,
             LoggingFormatCommon,
             LoggingFormatCommonServer,
             NoSwapOut,
             OperateWithSysPrv;

extern int  DclCgiPlusInSize,
            DclSysCommandSize,
            DclSysOutputSize,
            DclCgiVariablePrefixLength,
            FileBufferSize,
            InstanceGroupNumber,
            NetReadBufferSize,
            OutputBufferSize,
            ProcessPriority,
            ServerPort;

extern char  *AuthPromiscuousPwdPtr;

extern char  ControlBuffer[],
             DclCgiVariablePrefix[],
             LoggingFileName[],
             LoggingFormatUser[],
             LoggingPeriodName[],
             PersonaIdentName[],
             SesolaParams[],
             SoftwareID[],
             Utility[];
 
/****************************************************************************/
/*
This function allows images activated by a "foreign verb" to behave in a way 
that approximates the CLI$ (Command Line Interpreter) utility calls.  Get the 
entire command line following the verb that activated the image.  The command 
line is returned in uppercase, space compressed (i.e. maximum of one space 
between text elements, trimmed of leading and trailing spaces).  Returns a 
warning status if there were no parameters/qualifiers on the command line.
The variable CommandLine is global.
*/ 
 
int ParseCommandLine ()
 
{
   int  status;
   unsigned short  Length;
   unsigned long  Flags = 0;
   char  *cptr;
   $DESCRIPTOR (CommandLineDsc, CommandLine);
 
   if (!(cptr = getenv ("HTTPD$PARAM")))
   {
      /* get the entire command line following the verb */
      if (VMSnok (status =
          lib$get_foreign (&CommandLineDsc, 0, &Length, &Flags)))
         return (status);
      CommandLine[Length] = '\0';
   }
   else
   {
      strncpy (CommandLine, cptr, sizeof(CommandLine));
      CommandLine[sizeof(CommandLine)-1] = '\0';
   }

   if (ParseCommand (CommandLine))
      return (SS$_NORMAL);
   else
      return (STS$K_ERROR | STS$M_INHIB_MSG);
}
 
/****************************************************************************/
/*
This function allows images activated by a "foreign verb" to behave in a way 
that approximates the CLI$ (Command Line Interpreter) utility calls.  Quoted 
strings are always indicated by being parsed to include a single leading 
quote.
*/ 
 
BOOL ParseCommand (char *CommandLine)
 
{
   BOOL  CommandLineOK = true;
   int  QuoteCount = 0;
   char  *cptr, *eptr;
   char  Entity [256] = "";
 
   /* set up any argument defaults */
   ParseCommandEntity (NULL);
 
   cptr = CommandLine;
   eptr = Entity;
 
   for (;;)
   {
      if (*cptr == '\"')
      {
         QuoteCount++;
         *eptr++ = *cptr++;
         continue;
      }
 
      if (QuoteCount & 1 && *cptr)
      {
         /* inside quoted text, copy all characters as literals */
         *eptr++ = *cptr++;
         continue;
      }
 
      if (*cptr == '/' || ISLWS (*cptr) || !*cptr)
      {
         if (ISLWS (*cptr))
         {
            /* span the white space */
            while (*cptr && ISLWS (*cptr)) cptr++;
            if (*cptr == '=')
            {
               /* part of a qualifier, continue to get the value */
               *eptr++ = *cptr++;
               /* span any intervening white space */
               while (*cptr && ISLWS (*cptr)) cptr++;
               continue;
            }
         }
 
         if (Entity[0])
         {
            *eptr = '\0';
            if (!ParseCommandEntity (Entity)) CommandLineOK = false;
         }
 
         /* if end of command line then break from loop */
         if (!*cptr) break;
 
         /* start of new entity */
         eptr = Entity;
         /* if start of qualifier ensure slash is copied */
         if (*cptr == '/') *eptr++ = *cptr++;
 
         continue;
      }
 
      /* any other character, just copy, ensure upper case */
      *eptr++ = toupper(*cptr++);
   }
 
   return (CommandLineOK);
}
 
/*****************************************************************************/
/*
Get a string value from a qualifier, e.g. '/EXAMPLE=TEST'.
*/
 
BOOL ParseCommandString
(
char *Entity,
char *String,
BOOL Qualifier,
BOOL ReportErrors,
BOOL EnsureUpperCase
)
{
   int  QuoteCount = 0;
   char  *eptr, *sptr;
 
   if (Debug) fprintf (stdout, "ParseCommandString()\nEntity: '%s'\n", Entity);
 
   eptr = Entity;
 
   if (Qualifier)
   {
      /* scan down to equate symbol */
      while (*eptr && *eptr != '=') eptr++;
      if (*eptr) eptr++;
      if (!*eptr)
      {
         if (ReportErrors)
         {
            fprintf (stdout,
"%%%s-E-VALREQ, missing qualifier or keyword value\n \\%s\\\n",
            Utility, Entity+1);
         }
         return (false);
      }
   }
 
   sptr = String;
   while (*eptr)
   {
      if (*eptr == '\"')
      {
         if (QuoteCount & 1)
         {
            /* are inside quotes, check for escaped quotes ("") */
            if (*++eptr != '\"')
            {
               /* now outside quotes */
               QuoteCount++;
            }
            /* drop thru to character copy */
         }
         else
         {
            /* now inside quotes */
            QuoteCount++;
            eptr++;
            continue;
         }
      }
 
      if (EnsureUpperCase)
         *sptr++ = toupper(*eptr++);
      else
         *sptr++ = *eptr++;
   }
   *sptr = '\0';
 
   if (Debug) fprintf (stdout, "String: '%s'\n", String);
 
   return (true);
}
 
/*****************************************************************************/
/*
Get an integer value from a qualifier, e.g. '/EXAMPLE=99'.
*/
 
BOOL ParseCommandInteger
(
char *Entity,
int *IntegerPtr,
int Base,
BOOL ReportErrors
)
{
   char  *eptr, *sptr;
 
   if (Debug)
      fprintf (stdout, "ParseCommandInteger() '%s' Base: %d\n", Entity, Base);
 
   for (eptr = Entity; *eptr && *eptr != '='; eptr++);
   if (*eptr) eptr++;
   if (*eptr)
   {
      *IntegerPtr = strtol (eptr, &sptr, Base);
      if (sptr > eptr && !*sptr)
         return (true);
      else
      {
         if (ReportErrors)
         {
            fprintf (stdout,
            "%%%s-E-BADVALUE, '%s' is an invalid keyword value\n",
            Utility, eptr);
         }
         return (false);
      }
   }
   else
   {
      if (ReportErrors)
      {
         fprintf (stdout,
"%%%s-E-VALREQ, missing qualifier or keyword value\n \\%s\\\n",
         Utility, Entity+1);
      }
      return (false);
   }
}
 
/*****************************************************************************/
/*
A single command line "entity" has been parsed, check if its recognised.  This 
function is the one modified for the individual requirements of each program.
*/
 
BOOL ParseCommandEntity (char *Entity)
 
{
   BOOL  ok;
   int  Length;
   char  Scratch [256];
   char  *cptr, *sptr, *tptr, *zptr;

   if (!Entity)
   {
      /* set up any argument defaults */
      return (true);
   }

   if (Debug) fprintf (stdout, "ParseCommandEntity() Entity: '%s'\n", Entity);
 
   ok = false;

   if (Entity[0] == '/')
   {
      if (strsame (Entity, "/ACCEPT=", 4))
      {
         ok = ParseCommandString (Entity, Scratch, true, true, true);
         for (cptr = Scratch; *cptr && ISLWS(*cptr); cptr++);
         if (!*cptr) return (ok);
         CliAcceptHostsPtr = VmGet (Length = strlen(Scratch)+1);
         memcpy (CliAcceptHostsPtr, Scratch, Length);
         return (ok);
      }

      if (strsame (Entity, "/AUTHORIZE=", 4))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (*cptr) cptr++;
         while (*cptr)
         {
            while (*cptr == '(' || *cptr == ',' || *cptr == ')') cptr++;
            zptr = (sptr = Scratch) + sizeof(Scratch)-1;
            while (*cptr && *cptr != ',' && *cptr != ')' && sptr < zptr)
               *sptr++ = *cptr++;
            *sptr = '\0';
            if (!Scratch[0]) continue;

            if (strsame (Scratch, "ALL", -1))
               AuthPolicyAuthorizedOnly = ok = true;
            else
            if (strsame (Scratch, "SSL", -1))
               AuthPolicySslOnly = ok = true;
            else
            {
               fprintf (stdout,
"%%%s-E-IVKEYW, unrecognized keyword\n \\%s\\\n",
                        Utility, Scratch);
               return (false);
            }
         }
         if (!ok)
            fprintf (stdout,
"%%%s-E-VALREQ, missing qualifier or keyword value\n \\%s\\\n",
                  Utility, Entity);
         return (true);
      }

      if (strsame (Entity, "/CACHE", 4))
      {
         CliCacheEnabled = true;
         CliCacheDisabled = false;
         return (true);
      }
      if (strsame (Entity, "/NOCACHE", 6))
      {
         CliCacheEnabled = false;
         CliCacheDisabled = true;
         return (true);
      }

      if (strsame (Entity, "/CGI_PREFIX=", 4))
      {
         ok = ParseCommandString (Entity, DclCgiVariablePrefix,
                                  true, true, true);
         DclCgiVariablePrefixLength = strlen(DclCgiVariablePrefix);
         return (ok);
      }

      if (strsame (Entity, "/CLUSTER=", 4) ||
          strsame (Entity, "/ALL=", 4))
      {
         ControlDoAllHttpd = true;
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (!*cptr) return (true);
         /* optional grouping number */
         return (ParseCommandInteger (Entity, &InstanceGroupNumber, 10, true));
      }

      if (strsame (Entity, "/DCLCGIPLUSIN=", 6))
         return (ParseCommandInteger (Entity, &DclCgiPlusInSize, 10, true));

      if (strsame (Entity, "/DETACH", 4)) return (CliDetach = true);

      if (strsame (Entity, "/DO=", 4))
         return (ParseCommandString (Entity, ControlBuffer, true, true, false));

#ifdef DBUG
      /* turns on all "if (Debug)" statements */
      if (strsame (Entity, "/DBUG", -1))
         return (Debug = true);
#endif

      if (strsame (Entity, "/DEMO", -1))
         return (CliDemo = true);

      if (strsame (Entity, "/FILBUF=", 5))
         return (ParseCommandInteger (Entity, &FileBufferSize, 10, true));

      if (strsame (Entity, "/FORMAT=", 4))
         return (ParseCommandString (Entity, LoggingFormatUser,
                                     true, true, false));

      if (strsame (Entity, "/GBLSEC=DELETE", 15))
      {
         CliGblSecDelete = true;
         return (true);
      }
      if (strsame (Entity, "/GBLSEC=NOPERM", 15))
      {
         CliGblSecNoPerm = true;
         return (true);
      }

      if (strsame (Entity, "/IDENT=", 4))
         return (ParseCommandString (Entity, CliProcessIdentName,
                                     true, true, true));

      if (strsame (Entity, "/NOINSTANCE", 6))
         return (CliInstanceNoCrePrc = true);
      if (strsame (Entity, "/INSTANCE=", 4))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (!*cptr) return (false);
         cptr++;
         if (strsame (cptr, "CPU", 3))
         {
            CliInstanceMax = INSTANCE_PER_CPU;
            return (true);
         }
         return (ParseCommandInteger (Entity, &CliInstanceMax, 10, true));
      }

      if (strsame (Entity, "/LOG=", 4))
      {
         CliLoggingEnabled = true;
         CliLoggingDisabled = false;
         if (Entity[4] == '=')
            return (ParseCommandString (Entity, LoggingFileName,
                                        true, true, true));
         else
            return (true);
      }
      if (strsame (Entity, "/NOLOG", 6))
      {
         CliLoggingEnabled = false;
         CliLoggingDisabled = true;
         return (true);
      }

      if (strsame (Entity, "/MONITOR", 4))
      {
         CliMonitorEnabled = true;
         CliMonitorDisabled = false;
         return (true);
      }
      if (strsame (Entity, "/NOMONITOR", 6))
      {
         CliMonitorEnabled = false;
         CliMonitorDisabled = true;
         return (true);
      }

      if (strsame (Entity, "/NETWORK", 5))
      {
         CliNetworkMode = true;
         CliNoNetworkMode = false;
         return (true);
      }
      if (strsame (Entity, "/NONETWORK", 5))
      {
         CliNetworkMode = false;
         CliNoNetworkMode = true;
         return (true);
      }

      if (strsame (Entity, "/NETBUF=", 5))
         return (ParseCommandInteger (Entity, &NetReadBufferSize, 10, true));

      if (strsame (Entity, "/OUTBUF=", 5))
         return (ParseCommandInteger (Entity, &OutputBufferSize, 10, true));

      if (strsame (Entity, "/PERIOD=", 5))
         return (ParseCommandString (Entity, LoggingPeriodName,
                                     true, true, false));

      if (strsame (Entity, "/PERSONA=", 5))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (!*cptr) return (CliPersonaEnabled = true);
         cptr++;
         while (*cptr)
         {
            while (*cptr == '(' || *cptr == ',' || *cptr == ')') cptr++;
            zptr = (sptr = Scratch) + sizeof(Scratch)-1;
            while (*cptr && *cptr != ',' && *cptr != ')' && sptr < zptr)
               *sptr++ = *cptr++;
            *sptr = '\0';
            if (!Scratch[0]) continue;

            if (strsame (Scratch, "AUTHORIZED", 4))
               CliPersonaAuthorized = true;
            else
            if (strsame (Scratch, "RELAXED", 5))
            {
               CliPersonaRelaxed = true;
               for (sptr = Scratch; *sptr && *sptr != '='; sptr++);
               if (strsame (sptr, "=AUTHORIZED", 5))
                  CliPersonaRelaxedAuthorized = true;
            }
            else
            if (strsame (Scratch, "IDENT=", 6))
            {
               strcpy (PersonaIdentName, Scratch+6);
               for (sptr = PersonaIdentName; *sptr; sptr++)
                  *sptr = toupper(*sptr);
            }
            else
            {
               strcpy (PersonaIdentName, Scratch);
               for (sptr = PersonaIdentName; *sptr; sptr++)
                  *sptr = toupper(*sptr);
            }
         }
         return (CliPersonaEnabled = true);
      }
      if (strsame (Entity, "/NOPERSONA", 5))
      {
         CliPersonaAuthorized = CliPersonaEnabled =
            CliPersonaRelaxed = CliPersonaRelaxedAuthorized = false;
         return (true);
      }

      if (strsame (Entity, "/PORT=", 4))
         return (ParseCommandInteger (Entity, &CliServerPort, 10, true));

      if (strsame (Entity, "/PRIORITY=", 4))
         return (ParseCommandInteger (Entity, &ProcessPriority, 10, true));

      if (strsame (Entity, "/PROFILE=", 5))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (*cptr)
         {
            cptr++;
            if (strsame (cptr, "NORULE", -1))
               AuthVmsUserProfileNoRule = true;
            else
            {
               fprintf (stdout,
"%%%s-E-IVKEYW, unrecognized keyword\n \\%s\\\n",
                        Utility, cptr);
               return (AuthVmsUserProfileEnabled = false);
            }
         }
         return (AuthVmsUserProfileEnabled = true);
      }
      if (strsame (Entity, "/NOPROFILE", 6))
      {
         AuthVmsUserProfileEnabled = false;
         return (true);
      }

      /* for testing only, also needs /SYSUAF=PROMSICUOUS if using SYSUAF! */
      if (strsame (Entity, "/PROMISCUOUS=", 5))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (*cptr)
         {
            cptr++;
            AuthPromiscuousPwdPtr = VmGet (Length = strlen(cptr)+1);
            memcpy (AuthPromiscuousPwdPtr, cptr, Length);
         }
         return (AuthPromiscuous = true);
      }
      if (strsame (Entity, "/NOPROMISCUOUS", 7))
      {
         AuthPromiscuous = false;
         return (true);
      }

      if (strsame (Entity, "/PROXY=", 5))
      {
         ok = ParseCommandString (Entity, CliProxyMaint, true, true, true);
         if (CliProxyMaint[0]) return (ok);
         fprintf (stdout,
"%%%s-E-VALREQ, missing qualifier or keyword value\n \\%s\\\n",
                  Utility, Entity);
         return (false);
      }

      if (strsame (Entity, "/REJECT=", 4))
      {
         ok = ParseCommandString (Entity, Scratch, true, true, true);
         for (cptr = Scratch; *cptr && ISLWS(*cptr); cptr++);
         if (!*cptr) return (ok);
         CliRejectHostsPtr = VmGet (Length = strlen(Scratch)+1);
         memcpy (CliRejectHostsPtr, Scratch, Length);
         return (ok);
      }

      if (strsame (Entity, "/SCRIPT=AS=", 4))
      {
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (*cptr) cptr++;
         while (*cptr && *cptr != '=') cptr++;
         if (*cptr)
         {
            cptr++;
            zptr = (sptr = CliScriptAs) + sizeof(CliScriptAs)-1;
            while (*cptr && sptr < zptr) *sptr++ = toupper(*cptr++);
            *sptr = '\0';
            if (CliScriptAs[0]) return (true);
         }
         fprintf (stdout,
"%%%s-E-VALREQ, missing qualifier or keyword value\n \\%s\\\n",
                  Utility, Entity);
         return (false);
      }

      if (strsame (Entity, "/SERVICES=", 4))
         return (ParseCommandString (Entity, CliServices, true, true, false));

      /* 
         This qualifier may come in handy if having to use VMS or WASD
         causes embarressment :^)  Seriously, if you consider providing
         the server identification a security issue use this qualifier
         to set it to something like "Mine", "Unknown", "?", etc.
      */
      if (strsame (Entity, "/SOFTWAREID=", 4))
         return (ParseCommandString (Entity, SoftwareID, true, true, false));

      if (strsame (Entity, "/SSL=", 4))
         return (ParseCommandString (Entity, SesolaParams, true, true, false));

      if (strsame (Entity, "/NOSSL", 6))
      {
         strcpy (SesolaParams, "/NOSSL");
         return (true);
      }

      if (strsame (Entity, "/SUBBUF=", 5))
         return (ParseCommandInteger (Entity, &DclSysOutputSize, 10, true));

      if (strsame (Entity, "/SWAP", -1))
      {
         NoSwapOut = false;
         return (true);
      }
      if (strsame (Entity, "/NOSWAP", -1))
         return (NoSwapOut = true);

      if (strsame (Entity, "/ODS5", -1))
      {
         CliOdsExtendedEnabled = true;
         CliOdsExtendedDisabled = false;
         return (true);
      }
      if (strsame (Entity, "/NOODS5", -1))
      {
         CliOdsExtendedEnabled = false;
         CliOdsExtendedDisabled = true;
         return (true);
      }

      if (strsame (Entity, "/SYSPRV", -1))
         return (OperateWithSysPrv = true);
      if (strsame (Entity, "/NOSYSPRV", -1))
      {
         OperateWithSysPrv = false;
         return (true);
      }

      if (strsame (Entity, "/SYSUAF=", 4))
      {
         AuthSysUafEnabled = true;
         for (cptr = Entity; *cptr && *cptr != '='; cptr++);
         if (!*cptr) return (true);
         cptr++;
         while (*cptr)
         {
            while (*cptr == '(' || *cptr == ',' || *cptr == ')') cptr++;
            zptr = (sptr = Scratch) + sizeof(Scratch)-1;
            while (*cptr && *cptr != ',' && *cptr != ')' && sptr < zptr)
               *sptr++ = *cptr++;
            *sptr = '\0';
            if (!Scratch[0]) continue;

            if (strsame (Scratch, "ALL", -1) ||
                strsame (Scratch, "RELAXED", -1))
               AuthPolicySysUafRelaxed = true;
            else
            if (strsame (Scratch, "ID", -1))
               AuthPolicySysUafIdentifiers = true;
            else
            if (strsame (Scratch, "PROXY", -1))
               AuthPolicySysUafProxy = true;
            else
            if (strsame (Scratch, "SSL", -1))
               AuthPolicySysUafSslOnly = true;
            else
            if (strsame (Scratch, "VMS", -1))
               AuthPolicySysUafVms = true;
            else
            if (strsame (Scratch, "WASD", -1) ||
                strsame (Scratch, "WASD_ID", -1))
               AuthPolicySysUafWasdIdentifiers = true;
            else
            {
               fprintf (stdout,
"%%%s-E-IVKEYW, unrecognized keyword\n \\%s\\\n",
                        Utility, Scratch);
               return (AuthSysUafEnabled = false);
            }
         }

         return (true);
      }
      if (strsame (Entity, "/NOSYSUAF", 6))
      {
         AuthSysUafEnabled = false;
         return (true);
      }

      /* for testing SYSUAF-authenticated security profiles purposes only */
      if (strsame (Entity, "/SYSUAF=PROMISCUOUS", -1))
         return (AuthSysUafEnabled = AuthSysUafPromiscuous = true);

      if (strsame (Entity, "/TESTS", 4))
         return (CliTests = true);

      if (strsame (Entity, "/USER=", 4))
         return (ParseCommandString (Entity, CliUserName, true, true, true));

      if (strsame (Entity, "/VERSION", 4))
         return (CliVersion = true);

      if (strsame (Entity, "/WATCH=", 4) ||
          strsame (Entity, "/NOWATCH", 6))
         return (WatchCliParse (Entity));

      if (strsame (Entity, "/ZERO", -1))
         return (AccountingZeroOnStartup = true);
      if (strsame (Entity, "/NOZERO", -1))
      {
         AccountingZeroOnStartup = false;
         return (true);
      }

      fprintf (stdout, "%%%s-E-IVQUAL, unrecognised qualifier\n \\%s\\\n",
               Utility, Entity+1);
      return (false);
   }
 
   if (!CliParameter[0])
      return (ParseCommandString (Entity, CliParameter, false, true, false));

   fprintf (stdout, "%%%s-E-MAXPARM, too many parameters\n \\%s\\\n",
            Utility, Entity);
   return (false);
}
   
/*****************************************************************************/

