View Javadoc
1   /*
2    * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  
27  package com.sun.jmx.snmp.IPAcl;
28  
29  
30  
31  // java import
32  //
33  import java.io.Serializable;
34  import java.io.File;
35  import java.io.FileInputStream;
36  import java.io.FileNotFoundException;
37  import java.net.InetAddress;
38  import java.net.UnknownHostException;
39  import java.util.Hashtable;
40  import java.util.logging.Level;
41  import java.util.Vector;
42  import java.util.Enumeration;
43  import java.util.HashSet;
44  import java.security.acl.AclEntry;
45  import java.security.acl.NotOwnerException;
46  
47  // SNMP Runtime import
48  //
49  import static com.sun.jmx.defaults.JmxProperties.SNMP_LOGGER;
50  import com.sun.jmx.snmp.InetAddressAcl;
51  
52  /**
53   * Defines an implementation of the {@link com.sun.jmx.snmp.InetAddressAcl InetAddressAcl} interface.
54   * <p>
55   * In this implementation the ACL information is stored on a flat file and
56   * its default location is "$JRE/lib/snmp.acl" - See
57   * {@link #getDefaultAclFileName()}
58   * <p>
59   * <OL>
60    *
61   * <p><b>This API is a Sun Microsystems internal API  and is subject
62   * to change without notice.</b></p>
63   */
64  
65  public class SnmpAcl implements InetAddressAcl, Serializable {
66      private static final long serialVersionUID = -6702287103824397063L;
67  
68      static final PermissionImpl READ  = new PermissionImpl("READ");
69      static final PermissionImpl WRITE = new PermissionImpl("WRITE");
70  
71      /**
72       * Constructs the Java Dynamic Management(TM) Access Control List
73       * based on IP addresses. The ACL will take the given owner name.
74       * The current IP address will be the owner of the ACL.
75       *
76       * @param Owner The name of the ACL Owner.
77       *
78       * @exception UnknownHostException If the local host is unknown.
79       * @exception IllegalArgumentException If the ACL file doesn't exist.
80       */
81      public SnmpAcl(String Owner)
82          throws UnknownHostException, IllegalArgumentException {
83          this(Owner,null);
84      }
85  
86      /**
87       * Constructs the Java Dynamic Management(TM) Access Control List
88       * based on IP addresses. The ACL will take the given owner name.
89       * The current IP address will be the owner of the ACL.
90       *
91       * @param Owner The name of the ACL Owner.
92       * @param aclFileName The name of the ACL File.
93       *
94       * @exception UnknownHostException If the local host is unknown.
95       * @exception IllegalArgumentException If the ACL file doesn't exist.
96       */
97      public SnmpAcl(String Owner, String aclFileName)
98          throws UnknownHostException, IllegalArgumentException {
99          trapDestList= new Hashtable<InetAddress, Vector<String>>();
100         informDestList= new Hashtable<InetAddress, Vector<String>>();
101 
102         // PrincipalImpl() take the current host as entry
103         owner = new PrincipalImpl();
104         try {
105             acl = new AclImpl(owner,Owner);
106             AclEntry ownEntry = new AclEntryImpl(owner);
107             ownEntry.addPermission(READ);
108             ownEntry.addPermission(WRITE);
109             acl.addEntry(owner,ownEntry);
110         } catch (NotOwnerException ex) {
111             if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
112                 SNMP_LOGGER.logp(Level.FINEST, SnmpAcl.class.getName(),
113                     "SnmpAcl(String,String)",
114                     "Should never get NotOwnerException as the owner " +
115                     "is built in this constructor");
116             }
117         }
118         if (aclFileName == null) setDefaultFileName();
119         else setAuthorizedListFile(aclFileName);
120         readAuthorizedListFile();
121     }
122 
123     /**
124      * Returns an enumeration of the entries in this ACL. Each element in the
125      * enumeration is of type <CODE>java.security.acl.AclEntry</CODE>.
126      *
127      * @return An enumeration of the entries in this ACL.
128      */
129     public Enumeration<AclEntry> entries() {
130         return acl.entries();
131     }
132 
133     /**
134      * Returns ann enumeration of community strings. Community strings are returned as String.
135      * @return The enumeration of community strings.
136      */
137     public Enumeration<String> communities() {
138         HashSet<String> set = new HashSet<String>();
139         Vector<String> res = new Vector<String>();
140         for (Enumeration<AclEntry> e = acl.entries() ; e.hasMoreElements() ;) {
141             AclEntryImpl entry = (AclEntryImpl) e.nextElement();
142             for (Enumeration<String> cs = entry.communities();
143                  cs.hasMoreElements() ;) {
144                 set.add(cs.nextElement());
145             }
146         }
147         String[] objs = set.toArray(new String[0]);
148         for(int i = 0; i < objs.length; i++)
149             res.addElement(objs[i]);
150 
151         return res.elements();
152     }
153 
154     /**
155      * Returns the name of the ACL.
156      *
157      * @return The name of the ACL.
158      */
159     public String getName() {
160         return acl.getName();
161     }
162 
163     /**
164      * Returns the read permission instance used.
165      *
166      * @return The read permission instance.
167      */
168     static public PermissionImpl getREAD() {
169         return READ;
170     }
171 
172     /**
173      * Returns the write permission instance used.
174      *
175      * @return  The write permission instance.
176      */
177     static public PermissionImpl getWRITE() {
178         return WRITE;
179     }
180 
181     /**
182      * Get the default name for the ACL file.
183      * In this implementation this is "$JRE/lib/snmp.acl"
184      * @return The default name for the ACL file.
185      **/
186     public static String getDefaultAclFileName() {
187         final String fileSeparator =
188             System.getProperty("file.separator");
189         final StringBuffer defaultAclName =
190             new StringBuffer(System.getProperty("java.home")).
191             append(fileSeparator).append("lib").append(fileSeparator).
192             append("snmp.acl");
193         return defaultAclName.toString();
194     }
195 
196     /**
197      * Sets the full path of the file containing the ACL information.
198      *
199      * @param filename The full path of the file containing the ACL information.
200      * @throws IllegalArgumentException If the passed ACL file doesn't exist.
201      */
202     public void setAuthorizedListFile(String filename)
203         throws IllegalArgumentException {
204         File file = new File(filename);
205         if (!file.isFile() ) {
206             if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
207                 SNMP_LOGGER.logp(Level.FINEST, SnmpAcl.class.getName(),
208                     "setAuthorizedListFile", "ACL file not found: " + filename);
209             }
210             throw new
211                 IllegalArgumentException("The specified file ["+file+"] "+
212                                          "doesn't exist or is not a file, "+
213                                          "no configuration loaded");
214         }
215         if (SNMP_LOGGER.isLoggable(Level.FINER)) {
216             SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
217                 "setAuthorizedListFile", "Default file set to " + filename);
218         }
219         authorizedListFile = filename;
220     }
221 
222     /**
223      * Resets this ACL to the values contained in the configuration file.
224      *
225      * @exception NotOwnerException If the principal attempting the reset is not an owner of this ACL.
226      * @exception UnknownHostException If IP addresses for hosts contained in the ACL file couldn't be found.
227      */
228     public void rereadTheFile() throws NotOwnerException, UnknownHostException {
229         alwaysAuthorized = false;
230         acl.removeAll(owner);
231         trapDestList.clear();
232         informDestList.clear();
233         AclEntry ownEntry = new AclEntryImpl(owner);
234         ownEntry.addPermission(READ);
235         ownEntry.addPermission(WRITE);
236         acl.addEntry(owner,ownEntry);
237         readAuthorizedListFile();
238     }
239 
240     /**
241      * Returns the full path of the file used to get ACL information.
242      *
243      * @return The full path of the file used to get ACL information.
244      */
245     public String getAuthorizedListFile() {
246         return authorizedListFile;
247     }
248 
249     /**
250      * Checks whether or not the specified host has <CODE>READ</CODE> access.
251      *
252      * @param address The host address to check.
253      *
254      * @return <CODE>true</CODE> if the host has read permission, <CODE>false</CODE> otherwise.
255      */
256     public boolean checkReadPermission(InetAddress address) {
257         if (alwaysAuthorized) return ( true );
258         PrincipalImpl p = new PrincipalImpl(address);
259         return acl.checkPermission(p, READ);
260     }
261 
262     /**
263      * Checks whether or not the specified host and community have <CODE>READ</CODE> access.
264      *
265      * @param address The host address to check.
266      * @param community The community associated with the host.
267      *
268      * @return <CODE>true</CODE> if the pair (host, community) has read permission, <CODE>false</CODE> otherwise.
269      */
270     public boolean checkReadPermission(InetAddress address, String community) {
271         if (alwaysAuthorized) return ( true );
272         PrincipalImpl p = new PrincipalImpl(address);
273         return acl.checkPermission(p, community, READ);
274     }
275 
276     /**
277      * Checks whether or not a community string is defined.
278      *
279      * @param community The community to check.
280      *
281      * @return <CODE>true</CODE> if the community is known, <CODE>false</CODE> otherwise.
282      */
283     public boolean checkCommunity(String community) {
284         return acl.checkCommunity(community);
285     }
286 
287     /**
288      * Checks whether or not the specified host has <CODE>WRITE</CODE> access.
289      *
290      * @param address The host address to check.
291      *
292      * @return <CODE>true</CODE> if the host has write permission, <CODE>false</CODE> otherwise.
293      */
294     public boolean checkWritePermission(InetAddress address) {
295         if (alwaysAuthorized) return ( true );
296         PrincipalImpl p = new PrincipalImpl(address);
297         return acl.checkPermission(p, WRITE);
298     }
299 
300     /**
301      * Checks whether or not the specified host and community have <CODE>WRITE</CODE> access.
302      *
303      * @param address The host address to check.
304      * @param community The community associated with the host.
305      *
306      * @return <CODE>true</CODE> if the pair (host, community) has write permission, <CODE>false</CODE> otherwise.
307      */
308     public boolean checkWritePermission(InetAddress address, String community) {
309         if (alwaysAuthorized) return ( true );
310         PrincipalImpl p = new PrincipalImpl(address);
311         return acl.checkPermission(p, community, WRITE);
312     }
313 
314     /**
315      * Returns an enumeration of trap destinations.
316      *
317      * @return An enumeration of the trap destinations (enumeration of <CODE>InetAddress</CODE>).
318      */
319     public Enumeration<InetAddress> getTrapDestinations() {
320         return trapDestList.keys();
321     }
322 
323     /**
324      * Returns an enumeration of trap communities for a given host.
325      *
326      * @param i The address of the host.
327      *
328      * @return An enumeration of trap communities for a given host (enumeration of <CODE>String</CODE>).
329      */
330     public Enumeration<String> getTrapCommunities(InetAddress i) {
331         Vector<String> list = null;
332         if ((list = trapDestList.get(i)) != null ) {
333             if (SNMP_LOGGER.isLoggable(Level.FINER)) {
334                 SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
335                     "getTrapCommunities", "["+i.toString()+"] is in list");
336             }
337             return list.elements();
338         } else {
339             list = new Vector<>();
340             if (SNMP_LOGGER.isLoggable(Level.FINER)) {
341                 SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
342                     "getTrapCommunities", "["+i.toString()+"] is not in list");
343             }
344             return list.elements();
345         }
346     }
347 
348     /**
349      * Returns an enumeration of inform destinations.
350      *
351      * @return An enumeration of the inform destinations (enumeration of <CODE>InetAddress</CODE>).
352      */
353     public Enumeration<InetAddress> getInformDestinations() {
354         return informDestList.keys();
355     }
356 
357     /**
358      * Returns an enumeration of inform communities for a given host.
359      *
360      * @param i The address of the host.
361      *
362      * @return An enumeration of inform communities for a given host (enumeration of <CODE>String</CODE>).
363      */
364     public Enumeration<String> getInformCommunities(InetAddress i) {
365         Vector<String> list = null;
366         if ((list = informDestList.get(i)) != null ) {
367             if (SNMP_LOGGER.isLoggable(Level.FINER)) {
368                 SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
369                     "getInformCommunities", "["+i.toString()+"] is in list");
370             }
371             return list.elements();
372         } else {
373             list = new Vector<>();
374             if (SNMP_LOGGER.isLoggable(Level.FINER)) {
375                 SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
376                     "getInformCommunities", "["+i.toString()+"] is not in list");
377             }
378             return list.elements();
379         }
380     }
381 
382     /**
383      * Converts the input configuration file into ACL.
384      */
385     private void readAuthorizedListFile() {
386 
387         alwaysAuthorized = false;
388 
389         if (authorizedListFile == null) {
390             if (SNMP_LOGGER.isLoggable(Level.FINER)) {
391                 SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
392                     "readAuthorizedListFile", "alwaysAuthorized set to true");
393             }
394             alwaysAuthorized = true ;
395         } else {
396             // Read the file content
397             Parser parser = null;
398             try {
399                 parser= new Parser(new FileInputStream(getAuthorizedListFile()));
400             } catch (FileNotFoundException e) {
401                 if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
402                     SNMP_LOGGER.logp(Level.FINEST, SnmpAcl.class.getName(),
403                             "readAuthorizedListFile",
404                             "The specified file was not found, authorize everybody");
405                 }
406                 alwaysAuthorized = true ;
407                 return;
408             }
409 
410             try {
411                 JDMSecurityDefs n = parser.SecurityDefs();
412                 n.buildAclEntries(owner, acl);
413                 n.buildTrapEntries(trapDestList);
414                 n.buildInformEntries(informDestList);
415             } catch (ParseException e) {
416                 if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
417                     SNMP_LOGGER.logp(Level.FINEST, SnmpAcl.class.getName(),
418                         "readAuthorizedListFile", "Got parsing exception", e);
419                 }
420                 throw new IllegalArgumentException(e.getMessage());
421             } catch (Error err) {
422                 if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
423                     SNMP_LOGGER.logp(Level.FINEST, SnmpAcl.class.getName(),
424                         "readAuthorizedListFile", "Got unexpected error", err);
425                 }
426                 throw new IllegalArgumentException(err.getMessage());
427             }
428 
429             for(Enumeration<AclEntry> e = acl.entries(); e.hasMoreElements();) {
430                 AclEntryImpl aa = (AclEntryImpl) e.nextElement();
431                 if (SNMP_LOGGER.isLoggable(Level.FINER)) {
432                     SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
433                             "readAuthorizedListFile",
434                             "===> " + aa.getPrincipal().toString());
435                 }
436                 for (Enumeration<java.security.acl.Permission> eee = aa.permissions();eee.hasMoreElements();) {
437                     java.security.acl.Permission perm = eee.nextElement();
438                     if (SNMP_LOGGER.isLoggable(Level.FINER)) {
439                         SNMP_LOGGER.logp(Level.FINER, SnmpAcl.class.getName(),
440                                 "readAuthorizedListFile", "perm = " + perm);
441                     }
442                 }
443             }
444         }
445     }
446 
447     /**
448      * Set the default full path for "snmp.acl" input file.
449      * Do not complain if the file does not exists.
450      */
451     private void setDefaultFileName() {
452         try {
453             setAuthorizedListFile(getDefaultAclFileName());
454         } catch (IllegalArgumentException x) {
455             // OK...
456         }
457     }
458 
459 
460     // PRIVATE VARIABLES
461     //------------------
462 
463     /**
464      * Represents the Access Control List.
465      */
466     private AclImpl acl = null;
467     /**
468      * Flag indicating whether the access is always authorized.
469      * <BR>This is the case if there is no flat file defined.
470      */
471     private boolean alwaysAuthorized = false;
472     /**
473      * Represents the Access Control List flat file.
474      */
475     private String authorizedListFile = null;
476     /**
477      * Contains the hosts list for trap destination.
478      */
479     private Hashtable<InetAddress, Vector<String>> trapDestList = null;
480     /**
481      * Contains the hosts list for inform destination.
482      */
483     private Hashtable<InetAddress, Vector<String>> informDestList = null;
484 
485     private PrincipalImpl owner = null;
486 }