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

 * $Novell: ModifyACL.java,v 1.9 2003/08/21 11:35:09 $

 * Copyright (c) 2001 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.

 *

 * $name:         ModifyACL.java

 * $description:  modifyACL.java first modifies entryDN's ACL values to grant

 *                trusteeDN the read, write, and delete entry rights. It then

 *                displays entryDN's ACL values. Finally it removes entryDN's

 *                modified ACL value.

 *

 *                ACL (Access Control List) is a multivalued optional attribute.

 *                An entry's ACL values define which other entries (trustees)

 *                have what kinds of access to the entry itself and its

 *                attributes.

 *

 *                Each of the ACL value is in the format of

 *                    "privileges#scope#subjectname#protectedattrname".

 *                privileges:        ORed bits to indicate the rights.

 *                scope:             either 'entry' or 'subtree'.

 *                subjectname:       trustee DN.

 *                protectedattrname: [Entry Rights], or [All Attributes Rights],

 *                                   or a single attribute name.

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

import com.novell.ldap.LDAPAttribute;

import com.novell.ldap.LDAPAttributeSet;

import com.novell.ldap.LDAPConnection;

import com.novell.ldap.LDAPEntry;

import com.novell.ldap.LDAPException;

import com.novell.ldap.LDAPModification;

import com.novell.ldap.LDAPDSConstants;

import java.util.Enumeration;

import java.util.Iterator;

import java.io.UnsupportedEncodingException;



public class ModifyACL implements LDAPDSConstants {

    // nds [All Attribute Rights] flags

    //public static final int LDAP_DS_ENTRY_BROWSE     = 0x0001;

    //public static final int LDAP_DS_ENTRY_ADD        = 0x0002;

    //public static final int LDAP_DS_ENTRY_DELETE     = 0x0004;

    //public static final int LDAP_DS_ENTRY_RENAME     = 0x0008;

   // public static final int LDAP_DS_ENTRY_SUPERVISOR = 0x0010;

    // nds [Entry Rights] flags

    //public static final int LDAP_DS_ATTR_COMPARE     = 0x0001;

    //public static final int LDAP_DS_ATTR_READ        = 0x0002;

    //public static final int LDAP_DS_ATTR_WRITE       = 0x0004;

    //public static final int LDAP_DS_ATTR_SELF        = 0x0008;

    //public static final int LDAP_DS_ATTR_SUPERVISOR  = 0x0020;



    public static void main( String[] args )

    {

        if (args.length != 6) {

            System.err.println(

                "Usage:   java ModifyACL <host name> <port number> <login dn>"

                          + " <password> \n         <entry dn> <trustee dn>");

            System.err.println(

                "Example: java ModifyACL Acme.com 389 \"cn=Admin,o=Acme\""

                      + "  secret \n         \"cn=test,ou=Sales,o=Acme\" "

                                               + "\"cn=trustee,o=Acme\"");

            System.exit(1);

        }



        int privileges   = 0;

        int ldapVersion  = LDAPConnection.LDAP_V3;

        int ldapPort     = Integer.parseInt(args[1]);

        String ldapHost  = args[0];

        String loginDN   = args[2];

        String password  = args[3];

        String entryDN   = args[4];

        String trusteeDN = args[5];



        LDAPConnection lc = new LDAPConnection();



        // encode ACL value

        privileges |= LDAP_DS_ENTRY_BROWSE;

        privileges |= LDAP_DS_ENTRY_ADD;

        privileges |= LDAP_DS_ENTRY_DELETE;

        String aclValue = Integer.toString(privileges)+ "#" + "entry" + "#"

                                      + trusteeDN + "#" + "[Entry Rights]";



        try {

            // connect to the server

            lc.connect( ldapHost, ldapPort );

            // bind to the server

            lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));



            // modify entryDN's ACL attribute

            System.out.println( "    Entry DN: " + entryDN );

            System.out.println( "    Trustee DN: " + trusteeDN );

            System.out.println( "    Modifying entryDN's ACL value...");



            LDAPAttribute acl = new LDAPAttribute( "acl", aclValue);

            lc.modify( entryDN, new LDAPModification(LDAPModification.ADD, acl));

            System.out.println("    Modified ACL values to grant trusteeDN  the"

                     + "\n      'read', 'write', and 'delete' entry rights.\n");



            // display entryDN's ACL values

            findACLValues( lc, entryDN);



            // remove the Modified entryDN's ACL value

            System.out.println( "\n    Removing the modified ACL value..." );

            lc.modify( entryDN, new LDAPModification(LDAPModification.DELETE,acl));

            System.out.println( "    Removed modified ACL value." );



            lc.disconnect();

        }

        catch( LDAPException e ) {

            if ( e.getResultCode() == LDAPException.NO_SUCH_OBJECT )

               System.err.println( "Error: ModifyACL.java, No such entry" );

            else if ( e.getResultCode() ==

                                    LDAPException.INSUFFICIENT_ACCESS_RIGHTS )

               System.err.println("Error: ModifyACL.java, Insufficient rights");

            else if ( e.getResultCode() ==

                                       LDAPException.ATTRIBUTE_OR_VALUE_EXISTS )

               System.err.println("Error: ModifyACL.java, Attribute or value "

                                                                   + "exists");

            else {

               System.out.println( "Error: ModifyACL.java, " + e.toString() );

            }

            System.exit(1);

        }

        catch( UnsupportedEncodingException e ) {

            System.out.println( "Error: " + e.toString() );

        }

        System.exit(0);

    }



    // findACLValues() reads the entry to get it's ACL values

    public static void findACLValues(LDAPConnection lc, String entry) {

        String returnAttrs[] = { "acl" };

        String attributeName;

        Enumeration allValues;

        LDAPAttribute attribute;

        LDAPAttributeSet attributeSet;



        try {

            LDAPEntry aclList = lc.read( entry, returnAttrs );



            // printout entryDN's ACL values

            attributeSet = aclList.getAttributeSet();

            Iterator allAttributes = attributeSet.iterator();



            System.out.println("    =========================================");

            System.out.println("    entryDN's ACL values after modification:");

            System.out.println("    =========================================");

            if (allAttributes.hasNext()) {

                attribute = (LDAPAttribute)allAttributes.next();

                attributeName = attribute.getName();

                allValues = attribute.getStringValues();

                while(allValues.hasMoreElements()) {

                    PrintACLValue((String)allValues.nextElement());

                }

            }

        }

        catch( LDAPException e ) {

            System.out.println( "Error: ModdifyACL.java, " + e.toString() );

            System.exit(1);

        }

    }



    // PrintACLValue() parses and prints the ACLValue

    public static void PrintACLValue( String ACLValue ) {



        int    privileges;

        String scope, trusteeName, protName;



        // ACL value format: "privileges#scope#subjectname#protectedattrname".

        privileges = Integer.parseInt(

                         ACLValue.substring( 0, ACLValue.indexOf((int)'#')) );

        protName = ACLValue.substring(

                       ACLValue.lastIndexOf((int)'#') + 1, ACLValue.length());

        // truncate ACL value to "scope#subjectname"

        ACLValue = ACLValue.substring(

             ACLValue.indexOf((int)'#') + 1, ACLValue.lastIndexOf((int)'#') );

        scope = ACLValue.substring( 0, ACLValue.indexOf((int)'#') );

        trusteeName = ACLValue.substring(

                          ACLValue.indexOf((int)'#') + 1, ACLValue.length() );



        StringBuffer privs = new StringBuffer();

        if ( protName.equalsIgnoreCase("[Entry Rights]")) {

            // decode [Entry Rights]

            if ( (privileges & LDAP_DS_ENTRY_BROWSE) != 0 )

                privs.append("BrowseEntry ");

            if ( (privileges & LDAP_DS_ENTRY_ADD) != 0 )

                privs.append("AddEntry ");

            if ( (privileges & LDAP_DS_ENTRY_DELETE) != 0 )

                privs.append("DeleteEntry ");

            if ( (privileges & LDAP_DS_ENTRY_RENAME) != 0 )

                privs.append("RenameEntry ");

            if ( (privileges & LDAP_DS_ENTRY_SUPERVISOR) != 0 )

                privs.append("Supervisor");

         }

         else {

            // decode [All Attributes rights] and attribute rights

            if ( (privileges & LDAP_DS_ATTR_COMPARE) != 0 )

                privs.append("CompareAttributes ");

            if ( (privileges & LDAP_DS_ATTR_READ) != 0 )

                privs.append("ReadAttributes ");

            if ( (privileges & LDAP_DS_ATTR_WRITE) != 0 )

                privs.append("Write/Add/DeleteAttributes ");

            if ( (privileges & LDAP_DS_ATTR_SELF) != 0 )

                privs.append("Add/DeleteSelf ");

            if ( (privileges & LDAP_DS_ATTR_SUPERVISOR) != 0 )

                privs.append("Supervisor");

         }



        System.out.println("    Trustee name: " + trusteeName + "\n    scope: "

                               + scope + "\n    Protected attribute name: "

                               + protName + "\n    Privileges: " + privs);

        System.out.println("    ---------------------------------------------");

    }

}

