1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 package com.sun.dhcpmgr.server;
  26 
  27 import java.util.*;
  28 import java.net.InetAddress;
  29 
  30 import com.sun.dhcpmgr.bridge.*;
  31 import com.sun.dhcpmgr.data.*;
  32 
  33 /**
  34  * This class provides methods to manage the contents of the dhcptab.
  35  */
  36 
  37 public class DhcptabMgrImpl implements DhcptabMgr {
  38     private Bridge bridge;
  39 
  40     /**
  41      * Create a new DhcptabMgr using the provided native bridge.
  42      * @param bridge the native bridge class which actually does the work.
  43      */
  44     public DhcptabMgrImpl(Bridge bridge) {
  45         this.bridge = bridge;
  46     }
  47 
  48     /**
  49      * Create an option.
  50      * @param name the name of the option.
  51      * @param value the value for the option in dhcptab(4) format.
  52      * @return the Option.
  53      */
  54     public Option createOption(String name, String value)
  55         throws BridgeException {
  56         return bridge.createOption(name, value);
  57     }
  58 
  59     /**
  60      * Retrieve all options currently defined in the dhcptab.
  61      * @return an array of Options
  62      */
  63     public Option [] getOptions() throws BridgeException {
  64         return getOptions(null);
  65     }
  66 
  67     /**
  68      * Retrieve all options currently defined in the dhcptab.
  69      * @param datastore user-supplied datastore attributes
  70      * @return an array of Options
  71      */
  72     public Option [] getOptions(DhcpDatastore datastore)
  73         throws BridgeException {
  74         return bridge.getOptions(datastore);
  75     }
  76 
  77     /**
  78      * Retrieve all the macros currently defined in the dhcptab.
  79      * @return an array of Macros
  80      */
  81     public Macro [] getMacros() throws BridgeException {
  82         return getMacros(null);
  83     }
  84 
  85     /**
  86      * Retrieve all the macros currently defined in the dhcptab.
  87      * @param datastore user-supplied datastore attributes
  88      * @return an array of Macros
  89      */
  90     public Macro [] getMacros(DhcpDatastore datastore)
  91         throws BridgeException {
  92         /*
  93          * Load the vendor and site options before loading the macros
  94          * so we can validate correctly, adding them to the standard options
  95          * table.
  96          */
  97         OptionsTable optionsTable = OptionsTable.getTable();
  98         optionsTable.add(bridge.getOptions(datastore));
  99         return bridge.getMacros(datastore);
 100     }
 101 
 102     /**
 103      * Create a given record in the dhcptab, and signal the server to
 104      * reload the dhcptab if so requested.
 105      * @param rec the record to add to the table
 106      * @param signalServer true if the server is to be sent a SIGHUP
 107      */
 108     public void createRecord(DhcptabRecord rec, boolean signalServer)
 109             throws BridgeException {
 110         createRecord(rec, signalServer, null);
 111     }
 112 
 113     /**
 114      * Create a given record in the dhcptab, and signal the server to
 115      * reload the dhcptab if so requested.
 116      * @param rec the record to add to the table
 117      * @param signalServer true if the server is to be sent a SIGHUP
 118      * @param datastore user-supplied datastore attributes
 119      */
 120     public void createRecord(DhcptabRecord rec, boolean signalServer,
 121         DhcpDatastore datastore) throws BridgeException {
 122         bridge.createDhcptabRecord(rec, datastore);
 123         if (signalServer) {
 124             bridge.reload();
 125         }
 126     }
 127 
 128     /**
 129      * Modify a given record in the dhcptab, and signal the server to reload
 130      * the dhcptab if so requested
 131      * @param oldRec the current record to modify
 132      * @param newRec the new record to be placed in the table
 133      * @param signalServer true if the server is to be sent a SIGHUP
 134      */
 135     public void modifyRecord(DhcptabRecord oldRec, DhcptabRecord newRec,
 136             boolean signalServer) throws BridgeException {
 137         modifyRecord(oldRec, newRec, signalServer, null);
 138     }
 139 
 140     /**
 141      * Modify a given record in the dhcptab, and signal the server to reload
 142      * the dhcptab if so requested
 143      * @param oldRec the current record to modify
 144      * @param newRec the new record to be placed in the table
 145      * @param signalServer true if the server is to be sent a SIGHUP
 146      * @param datastore user-supplied datastore attributes
 147      */
 148     public void modifyRecord(DhcptabRecord oldRec, DhcptabRecord newRec,
 149         boolean signalServer, DhcpDatastore datastore)
 150         throws BridgeException {
 151         bridge.modifyDhcptabRecord(oldRec, newRec, datastore);
 152         if (signalServer) {
 153             bridge.reload();
 154         }
 155     }
 156 
 157     /**
 158      * Delete a given record from the dhcptab, and signal the server to reload
 159      * the dhcptab if so requested
 160      * @param rec the record to delete
 161      * @param signalServer true if the server is to be sent a SIGHUP
 162      */
 163     public void deleteRecord(DhcptabRecord rec, boolean signalServer)
 164             throws BridgeException {
 165         deleteRecord(rec, signalServer, null);
 166     }
 167 
 168     /**
 169      * Delete a given record from the dhcptab, and signal the server to reload
 170      * the dhcptab if so requested
 171      * @param rec the record to delete
 172      * @param signalServer true if the server is to be sent a SIGHUP
 173      * @param datastore user-supplied datastore attributes
 174      */
 175     public void deleteRecord(DhcptabRecord rec, boolean signalServer,
 176         DhcpDatastore datastore) throws BridgeException {
 177         bridge.deleteDhcptabRecord(rec, datastore);
 178         if (signalServer) {
 179             bridge.reload();
 180         }
 181     }
 182 
 183     /**
 184      * Delete a record by name and type
 185      * @param key The key for the record
 186      * @param type The type of record; either MACRO or OPTION
 187      */
 188     private void deleteRecord(String name, String type) throws BridgeException {
 189         DhcptabRecord rec = null;
 190         if (type.equals(DhcptabRecord.MACRO)) {
 191             rec = getMacro(name);
 192         } else {
 193             rec = getOption(name);
 194         }
 195         deleteRecord(rec, false);
 196     }
 197 
 198     /**
 199      * Delete a set of records.
 200      * @return An array of ActionError, one error for each record not deleted
 201      */
 202     private ActionError [] deleteRecords(DhcptabRecord [] recs) {
 203         ArrayList errorList = new ArrayList();
 204 
 205         for (int i = 0; i < recs.length; ++i) {
 206             try {
 207                 deleteRecord(recs[i], false);
 208             } catch (BridgeException e) {
 209                 errorList.add(new ActionError(recs[i].getKey(), e));
 210             }
 211         }
 212 
 213         return (ActionError[])errorList.toArray(new ActionError[0]);
 214     }
 215 
 216     private ActionError [] deleteAllRecords(String type)
 217             throws BridgeException {
 218         DhcptabRecord [] recs;
 219         if (type.equals(DhcptabRecord.MACRO)) {
 220             recs = getMacros();
 221         } else {
 222             recs = getOptions();
 223         }
 224         return deleteRecords(recs);
 225     }
 226 
 227     /**
 228      * Delete all macros
 229      * @return An array of ActionError, one error for each macro not deleted
 230      */
 231     public ActionError [] deleteAllMacros() throws BridgeException {
 232         return deleteAllRecords(DhcptabRecord.MACRO);
 233     }
 234 
 235     /**
 236      * Delete all options
 237      * @return An array of ActionError, one error for each option not deleted
 238      */
 239     public ActionError [] deleteAllOptions() throws BridgeException {
 240         return deleteAllRecords(DhcptabRecord.OPTION);
 241     }
 242 
 243     /**
 244      * Delete a list of macros identified by name
 245      * @param macroNames Names of the macros to delete
 246      * @return An array of ActionError, one element per macro not deleted
 247      */
 248     public ActionError [] deleteMacros(String [] macroNames) {
 249         ArrayList errorList = new ArrayList();
 250 
 251         for (int i = 0; i < macroNames.length; ++i) {
 252             try {
 253                 deleteRecord(macroNames[i], DhcptabRecord.MACRO);
 254             } catch (BridgeException e) {
 255                 errorList.add(new ActionError(macroNames[i], e));
 256             }
 257         }
 258 
 259         return (ActionError [])errorList.toArray(new ActionError[0]);
 260     }
 261 
 262     /**
 263      * Delete a list of options identified by name
 264      * @param optionNames Names of options to delete
 265      * @return An array of ActionError, one element per option not deleted
 266      */
 267     public ActionError [] deleteOptions(String [] optionNames) {
 268         ArrayList errorList = new ArrayList();
 269 
 270         for (int i = 0; i < optionNames.length; ++i) {
 271             try {
 272                 deleteRecord(optionNames[i], DhcptabRecord.OPTION);
 273             } catch (BridgeException e) {
 274                 errorList.add(new ActionError(optionNames[i], e));
 275             }
 276         }
 277 
 278         return (ActionError [])errorList.toArray(new ActionError[0]);
 279     }
 280 
 281     /**
 282      * Retrieve a given macro from the dhcptab.
 283      * @param key the key of the record to retrieve
 284      * @return the Macro for the given key
 285      */
 286     public Macro getMacro(String key)
 287         throws BridgeException {
 288         return getMacro(key, null);
 289     }
 290 
 291     /**
 292      * Retrieve a given macro from the dhcptab.
 293      * @param key the key of the record to retrieve
 294      * @param datastore user-supplied datastore attributes
 295      * @return the Macro for the given key
 296      */
 297     public Macro getMacro(String key, DhcpDatastore datastore)
 298         throws BridgeException {
 299         OptionsTable optionsTable = OptionsTable.getTable();
 300         optionsTable.add(bridge.getOptions(datastore));
 301         return bridge.getMacro(key, datastore);
 302     }
 303 
 304     /**
 305      * Retrieve a given option from the dhcptab.
 306      * @param key the key of the record to retrieve
 307      * @return the Option for the given key
 308      */
 309     public Option getOption(String key)
 310         throws BridgeException {
 311         return getOption(key, null);
 312     }
 313 
 314     /**
 315      * Retrieve a given option from the dhcptab.
 316      * @param key the key of the record to retrieve
 317      * @param datastore user-supplied datastore attributes
 318      * @return the Option for the given key
 319      */
 320     public Option getOption(String key, DhcpDatastore datastore)
 321         throws BridgeException {
 322         return bridge.getOption(key, datastore);
 323     }
 324 
 325     /**
 326      * Create a new dhcptab converting the one in the server's data store,
 327      * into a new data store.
 328      * @param datastore user-supplied datastore attributes
 329      */
 330     public void cvtDhcptab(DhcpDatastore datastore)
 331         throws BridgeException {
 332         bridge.cvtDhcptab(datastore);
 333     }
 334 
 335     /**
 336      * Create a new empty dhcptab in the server's data store, which must
 337      * already be configured.
 338      */
 339     public void createDhcptab() throws BridgeException {
 340         createDhcptab(null);
 341     }
 342 
 343     /**
 344      * Create a new empty dhcptab in the server's data store, which must
 345      * already be configured.
 346      * @param datastore user-supplied datastore attributes
 347      */
 348     public void createDhcptab(DhcpDatastore datastore)
 349         throws BridgeException {
 350         bridge.createDhcptab(datastore);
 351     }
 352 
 353     /**
 354      * Delete the server's dhcptab in the current data store.
 355      */
 356     public void deleteDhcptab() throws BridgeException {
 357         deleteDhcptab(null);
 358     }
 359 
 360     /**
 361      * Delete the server's dhcptab in the current data store.
 362      * @param datastore user-supplied datastore attributes
 363      */
 364     public void deleteDhcptab(DhcpDatastore datastore)
 365         throws BridgeException {
 366         bridge.deleteDhcptab(datastore);
 367     }
 368 
 369     public void createLocaleMacro()
 370         throws BridgeException, ValidationException {
 371         createLocaleMacro(null);
 372     }
 373 
 374     public void createLocaleMacro(DhcpDatastore datastore)
 375         throws BridgeException, ValidationException {
 376 
 377         Macro macro = new Macro();
 378         macro.setKey("Locale");
 379         macro.storeOption(StandardOptions.CD_TIMEOFFSET,
 380             String.valueOf(TimeZone.getDefault().getRawOffset()/1000));
 381 
 382         createRecord(macro, false);
 383     }
 384 
 385     public void createServerMacro(String svrName,
 386         InetAddress svrAddress, int leaseLength,
 387         boolean leaseNegotiable, String dnsDomain, Vector dnsServs)
 388         throws BridgeException, ValidationException {
 389 
 390         createServerMacro(svrName, svrAddress, leaseLength, leaseNegotiable,
 391             dnsDomain, dnsServs, null);
 392     }
 393 
 394     public void createServerMacro(String svrName,
 395         InetAddress svrAddress, int leaseLength,
 396         boolean leaseNegotiable, String dnsDomain, Vector dnsServs,
 397         DhcpDatastore datastore)
 398         throws BridgeException, ValidationException {
 399 
 400         Macro macro = new Macro();
 401         macro.setKey(svrName);
 402         macro.storeOption("Include", "Locale");
 403         macro.storeOption(StandardOptions.CD_TIMESERV, svrAddress);
 404         macro.storeOption(StandardOptions.CD_LEASE_TIME,
 405             String.valueOf(leaseLength));
 406         if (leaseNegotiable) {
 407             macro.storeOption(StandardOptions.CD_BOOL_LEASENEG, null);
 408         }
 409         if (dnsDomain != null && dnsDomain.length() != 0 &&
 410             dnsServs != null && dnsServs.size() != 0) {
 411             macro.storeOption(StandardOptions.CD_DNSDOMAIN, dnsDomain);
 412             macro.storeOption(StandardOptions.CD_DNSSERV, dnsServs);
 413         }
 414         // First delete it in case it's already there
 415         try {
 416             deleteRecord(macro, false);
 417         } catch (Throwable e) {
 418             // Ignore any error
 419         }
 420 
 421         createRecord(macro, false);
 422     }
 423 
 424     public synchronized void createNetworkMacro(Network network,
 425         IPAddress [] routers, boolean isLan, String nisDomain, Vector nisServs)
 426         throws BridgeException, ValidationException {
 427 
 428         createNetworkMacro(network, routers, isLan, nisDomain, nisServs,
 429             null);
 430     }
 431 
 432     public void createNetworkMacro(Network network,
 433         IPAddress [] routers, boolean isLan, String nisDomain, Vector nisServs,
 434         DhcpDatastore datastore) throws BridgeException, ValidationException {
 435 
 436         Macro macro = new Macro();
 437         macro.setKey(network.toString());
 438         macro.storeOption(StandardOptions.CD_SUBNETMASK, network.getMask());
 439         if (routers == null) {
 440             macro.storeOption(StandardOptions.CD_ROUTER_DISCVRY_ON, "1");
 441         } else {
 442             for (int i = 0; i < routers.length; i++) {
 443                 macro.storeOption(StandardOptions.CD_ROUTER, routers[i]);
 444             }
 445         }
 446 
 447         if (isLan) {
 448             macro.storeOption(StandardOptions.CD_BROADCASTADDR,
 449                 network.getBroadcastAddress());
 450         }
 451 
 452         // NIS config
 453         if (nisDomain != null && nisDomain.length() != 0 &&
 454             nisServs != null && nisServs.size() != 0) {
 455             macro.storeOption(StandardOptions.CD_NIS_DOMAIN, nisDomain);
 456             macro.storeOption(StandardOptions.CD_NIS_SERV, nisServs);
 457         }
 458 
 459         createRecord(macro, false);
 460     }
 461 }