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

  $Archive: $
  $Revision: $
  $Modtime: $
 
 Copyright (c) 1998 Novell, Inc. All Rights Reserved.

 THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
 ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
 PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
 ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
 PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
 DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
 PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
 CUSTOMERS WITH RESPECT TO THIS CODE.

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

/**************************************************************************
   READACL.C
***************************************************************************

  This program accepts an object name and reads all ACL entries for 
  that object. If no object parameter is passed in, the currently 
  authenticated object is used.

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ntypes.h>
#include <nwnet.h>
#include <nwcalls.h>
#include <nwlocale.h>

/* Globals */

NWDSContextHandle context;
nbool8            bbDoLogout = N_FALSE;

/* Prototypes */

void ShowUsage(void);
int  ReadAclValues(NWDSContextHandle context, pnstr8 sourceObject);
int  Proc(pnstr8);
void InitDS(void);
void UninitDS(void);
void DecodeRights(pnstr8 attrName, pnstr8 rightsstring, nuint32 privs);

/***************************************************************************
**   Main Program
*/
void main(int argc, char *argv[])
{
   
   switch(argc)
   {
      case 1:   /* No arguments */
      {
         InitDS();
         Proc(NULL);
         break;
      }
      case 2:  /* One argument */
      {
         if(!strcmp(argv[1],"/?"))
            ShowUsage();        /* exits */

         InitDS();
         Proc(argv[1]);
         break;
      }
      default:  /* Two or more args */
      {
         ShowUsage();
      }
   }
   
   UninitDS();
}

/***************************************************************************
**   Print program usage statement
*/
void ShowUsage(void)
{
   printf("\nUsage: readacl [<object>]\n");
   printf("\n<object> name of the object to which the ACL is read.\n");
   printf("Not specifying the <object> defaults to the currently\n");
   printf("authenticated user.\n");
   exit(1);
}

/***************************************************************************
**   Read and print ACL values from an object.
*/
int ReadAclValues(NWDSContextHandle context, pnstr8 currObject)
{
   NWDSCCODE       ccode;
   nuint32         totalAttrs, totalValues, x;
   nuint32         syntaxID;
   nuint32         attrValSize;
   nint32          iterHandle = NO_MORE_ITERATIONS;
   nstr8           name[3+1];          /* never anything but "ACL"   */   
   pObject_ACL_T   acl;
   pBuf_T          inBuf, outBuf;
   char            rightsstr[9] = "";  /* string format of "[CRWAS]" */

   ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &inBuf);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %04X", ccode);
      goto ReadAclValuesExit0;
   }

   ccode = NWDSAllocBuf(MAX_DN_CHARS, &outBuf);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %04X", ccode);
      goto ReadAclValuesExit1;
   }

   ccode = NWDSInitBuf(context,DSV_READ,inBuf);
   if(ccode)
   {
      printf("\nNWDSInitBuf returned %04X", ccode);
      goto ReadAclValuesExit2;
   }

   ccode = NWDSPutAttrName(context,inBuf,"ACL");  /* We only want the */
   if(ccode)                                      /* attribute ACL    */
   {
      printf("\nNWDSPutAttrName returned %04X", ccode);
      goto ReadAclValuesExit2;
   }

   do
   {
      ccode = NWDSRead(
               /* context handle       */  context,
               /* name of object       */  currObject,          
               /* read name and val    */  DS_ATTRIBUTE_VALUES, 
               /* only attr. specified */  FALSE,               
               /* buffer holding "ACL" */  inBuf,               
               /* loop counter         */  &iterHandle,         
               /* output buffer        */  outBuf);             
      if(ccode)
      {
         printf("\nNWDSRead returned %04X", ccode);
         goto ReadAclValuesExit2;
      }

      ccode = NWDSGetAttrCount(context, outBuf, &totalAttrs);
      if(ccode)
      {
         printf("\nNWDSGetAttrCount returned %04X", ccode);
         goto ReadAclValuesExit2;
      }

      if((nuint32)0 == totalAttrs)
         goto ReadAclValuesExit2;

      ccode = NWDSGetAttrName(
                /* context handle    */  context,
                /* values            */  outBuf,       
                /* ACL               */  name,         
                /* number of values  */  &totalValues, 
                /* how to read value */  &syntaxID);   
      if(ccode)
      {
         printf("NWDSGetAttrName returned %04X", ccode);
         goto ReadAclValuesExit2;
      }
      
      if(syntaxID != SYN_OBJECT_ACL)
      {
         printf("Error NWDSGetAttrName, bad syntax\n");
         goto ReadAclValuesExit2;
      }

      for(x = totalValues; x; x--)
      {
         ccode = NWDSComputeAttrValSize(
                   /* context handle   */  context,     
                   /* buffer with info */  outBuf,      
                   /* syntax ID        */  syntaxID,    
                   /* size to allocate */  &attrValSize);
         if(ccode)
         {
            printf("NWDSComputeAttrValSize returned %04X", ccode);
            goto ReadAclValuesExit2;
         }

         acl = malloc((size_t)attrValSize); 
         if(!acl)
         {
            printf("\nError allocating memory for acl");
            goto ReadAclValuesExit2;
         }
         ccode = NWDSGetAttrVal(
                   /* context handle (IN)   */ context,   
                   /* buffer with info (IN) */ outBuf,    
                   /* syntax ID (IN)        */ syntaxID,  
                   /* value of attrib (OUT) */ acl);      
         if(ccode)
         {
            printf("Error NWDSGetAttrVal\n");
            goto ReadAclValuesExit2;
         }

         DecodeRights(acl->protectedAttrName, rightsstr, acl->privileges);
         printf("%-35s %-9s %-20s\n",
                 acl->protectedAttrName,
                 rightsstr, acl->subjectName);

         free(acl);
      }
   }
   while(iterHandle != NO_MORE_ITERATIONS);


ReadAclValuesExit2:
   NWDSFreeBuf(inBuf);

ReadAclValuesExit1:
   NWDSFreeBuf(outBuf);

ReadAclValuesExit0:
   return (ccode);
}

/***************************************************************************
**   Use current user or object passed in at command line.
*/
int Proc(pnstr8 inname)
{
   NWDSCCODE   ccode;
   nstr8       DN[MAX_DN_BYTES + 1];
   nstr8       currName[MAX_DN_BYTES + 1] = "";

   ccode=NWDSGetContext(context, DCK_NAME_CONTEXT, DN);
   if(ccode)
   {
      printf("\nNWDSGetContext returned %04X", ccode);
      return(ccode);
   }

   if(inname == NULL)
   {
      ccode = NWDSWhoAmI(context, currName);
      if (ccode)
      {
         printf("\nNWDSWhoAmI returned %04X", ccode);
         return(ccode);
      }
   }
   else
   {
       strcpy(currName, inname);
   }
      
   printf("Current Context: %s\n", DN);
   printf(" ACLs of Object: %s\n\n", currName);
   printf("  ATTRIBUTE NAMES                   RIGHTS    SUBJECTS \n");
   printf("---------------------               -------   --------- \n");

   ccode = ReadAclValues(context, currName);
   if(ccode)
   {
      printf("\nError readAclValues %X\n",ccode);
   }
   
   return(ccode);
}

/***************************************************************************
**   Establish context, standard initializations for DS calls
*/
void InitDS(void)
{
   NWDSCCODE   ccode;
   LCONV       lconvInfo;
   nstr8       strUserName[NW_MAX_USER_NAME_LEN];
   nstr8       strUserPassword[50];

   /* Initialize libraries */
   ccode=NWCallsInit(NULL,NULL);
   if(ccode)       
   {
      printf("\nNWCallsInit returned %04X", ccode);
      exit(1);
   }

   NWLlocaleconv(&lconvInfo);

   ccode = NWInitUnicodeTables(lconvInfo.country_id, lconvInfo.code_page);
   if(ccode)
   {
      printf("\nNWInitUnicodeTables returned %04X", ccode);
      exit(1);
   }

   ccode = NWDSCreateContextHandle(&context);
   if(ccode)
   {
      printf("\nNWDSCreateContextHandle returned %04X", ccode);
      NWFreeUnicodeTables();
      exit(1);
   }

   /*  Must authenticate if not already authenticated to NDS
       (which will always be the case if this example is 
       compiled and run as an NLM).  */
   if(!NWIsDSAuthenticated())
   {
      printf("\nMust authenticate to NDS");
      printf("\nEnter User Name: ");
      gets(strUserName);
      printf("Enter User Password: ");
      gets(strUserPassword);

      ccode = NWDSLogin(context, 0, strUserName, strUserPassword, 0);
      if(ccode)
      {
         printf("\nNWDSLogin returned %X", ccode);
         NWDSFreeContext(context);
         NWFreeUnicodeTables();
         exit(1);
      }

      /* If example logs in, it will also log out */
      bbDoLogout = N_TRUE;
   }
}

/***************************************************************************
**   Release context and clean up.
*/
void UninitDS()
{
   NWDSCCODE   ccode;

   if(bbDoLogout)
   {
      ccode = NWDSLogout(context);
      if(ccode)
      {
         printf("\nNWDSLogout returned %04X", ccode);
      }
   }

   ccode=NWDSFreeContext(context);
   if(ccode)
   {
      printf("\nNWDSFreeContext returned %04X", ccode);
   }

   ccode=NWFreeUnicodeTables();
   if(ccode)
   {
      printf("\nNWFreeUnicodeTables returned %04X", ccode);
   }
}

/***************************************************************************
**   Build rights string of the format [CRWAS] from privs
*/
void DecodeRights(pnstr8 attrName, pnstr8 rightsstring, nuint32 privs)
{
   strset(rightsstring, '\x0');
   strcat(rightsstring, "[");
   if(!strcmp(attrName, "[Entry Rights]"))
   {
      if(privs & 0x01)                  /* DS_ENTRY_BROWSE     */
         strcat(rightsstring, "B");
      else
         strcat(rightsstring, " ");
      if(privs & 0x02)                  /* DS_ENTRY_ADD        */
         strcat(rightsstring, "A");
      else
         strcat(rightsstring, " ");
      if(privs & 0x04)                  /* DS_ENTRY_DELETE     */
         strcat(rightsstring, "D");
      else
         strcat(rightsstring, " ");
      if(privs & 0x08)                  /* DS_ENTRY_RENAME     */
         strcat(rightsstring, "R");
      else
         strcat(rightsstring, " ");
      if(privs & 0x10)                  /* DS_ENTRY_SUPERVISOR */
         strcat(rightsstring, "S");
      else
         strcat(rightsstring, " ");
   }
   else
   {
      if(!strcmp(attrName, "[SMS Rights]"))
      {
         if(privs & 0x01)                   /* DS_SMS_SCAN     */
            strcat(rightsstring, "S");
         else
            strcat(rightsstring, " ");
         if(privs & 0x02)                   /* DS_SMS_BACKUP   */
            strcat(rightsstring, "B");
         else
            strcat(rightsstring, " ");
         if(privs & 0x04)                   /* DS_SMS_RESTORE  */
            strcat(rightsstring, "R");
         else
            strcat(rightsstring, " ");
         if(privs & 0x08)                   /* DS_SMS_RENAME   */
            strcat(rightsstring, "C");
         else
            strcat(rightsstring, " ");
         if(privs & 0x10)                   /* DS_SMS_DELETE   */
            strcat(rightsstring, "D");
         else
            strcat(rightsstring, " ");
         if(privs & 0x20)                   /* DS_SMS_ADMIN    */
            strcat(rightsstring, "A");
         else
            strcat(rightsstring, " ");
      }
      else    /* Attribute Rights which applies to all others     */
      {
         if(privs & 0x01)                   /* DS_ATTR_COMPARE    */
            strcat(rightsstring, "C");
         else
            strcat(rightsstring, " ");
         if(privs & 0x02)                   /* DS_ATTR_READ       */
            strcat(rightsstring, "R");
         else
            strcat(rightsstring, " ");
         if(privs & 0x04)                   /* DS_ATTR_WRITE      */
            strcat(rightsstring, "W");
         else
            strcat(rightsstring, " ");
         if(privs & 0x08)                   /* DS_ATTR_SELF       */
            strcat(rightsstring, "A");
         else
            strcat(rightsstring, " ");
         if(privs & 0x20)                   /* DS_ATTR_SUPERVISOR */
            strcat(rightsstring, "S");
         else
            strcat(rightsstring, " ");
      }
   }
   strcat(rightsstring,"]\x0");
} 
