function subnet_modify($options = "") { global $conf, $self, $onadb; //printmsg('DEBUG => subnet_modify('.implode (";",$options).') called', 3); // Version - UPDATE on every edit! $version = '1.08'; // Parse incoming options string to an array $options = parse_options($options); // Return the usage summary if we need to if ($options['help'] or !$options['subnet'] or !($options['set_ip'] or $options['set_netmask'] or $options['set_type'] or $options['set_name'] or array_key_exists('set_vlan', $options) or $options['set_security_level'])) { // NOTE: Help message lines should not exceed 80 characters for proper display on a console $self['error'] = 'ERROR => Insufficient parameters'; return array(1, <<<EOM subnet_modify-v{$version} Modify a subnet (subnet) record Synopsis: subnet_modify [KEY=VALUE] ... Where: subnet=[ID|IP] select subnet by search string Update: set_ip=IP change subnet "subnet" address set_netmask=MASK change subnet netmask set_name=TEXT change subnet name (i.e. "LAN-1234") set_type=TYPE change subnet type by name or id set_vlan=VLAN change vlan by name, number campus=CAMPUS vlan campus name or id to help identify vlan set_security_level=LEVEL numeric security level ({$conf['ona_lvl']}) EOM ); } $check_boundaries = 0; // Find the subnet record we're modifying list($status, $rows, $subnet) = ona_find_subnet($options['subnet']); if ($status or !$rows) { $self['error'] = "ERROR => Subnet not found"; return array(2, $self['error'] . "\n"); } // Check permissions if (!auth('subnet_modify')) { $self['error'] = "Permission denied!"; printmsg($self['error'], 0); return array(3, $self['error'] . "\n"); } // Validate the ip address if (!$options['set_ip']) { $options['set_ip'] = $subnet['ip_addr']; } else { $check_boundaries = 1; $options['set_ip'] = $setip = ip_mangle($options['set_ip'], 'numeric'); // FIXME: what if ip_mangle returns a GMP object? if ($options['set_ip'] == -1) { $self['error'] = "ERROR => The IP address specified is invalid!"; return array(4, $self['error'] . "\n"); } } // Validate the netmask is okay if (!$options['set_netmask']) { $options['set_netmask'] = $subnet['ip_mask']; $cidr = ip_mangle($options['set_netmask'], 'cidr'); } else { $check_boundaries = 1; $cidr = ip_mangle($options['set_netmask'], 'cidr'); // FIXME: what if ip_mangle returns a GMP object? $options['set_netmask'] = ip_mangle($options['set_netmask'], 'numeric'); if ($cidr == -1 or $options['set_netmask'] == -1) { $self['error'] = "ERROR => The netmask specified is invalid!"; return array(5, $self['error'] . "\n"); } } if (is_ipv4($setip)) { $padding = 32; $fmt = 'dotted'; $ip1 = ip_mangle($setip, 'binary'); $num_hosts = 0xffffffff - $options['set_netmask']; $first_host = $options['set_ip'] + 1; $last_host = $options['set_ip'] + $num_hosts; $str_last_host = $last_host; $last_last_host = $last_host - 1; } else { $padding = 128; $fmt = 'ipv6gz'; $ip1 = ip_mangle($setip, 'bin128'); $first_host = gmp_strval(gmp_add($options['set_ip'], 1)); $sub = gmp_sub("340282366920938463463374607431768211455", $options['set_netmask']); $last_host = gmp_add($options['set_ip'], $sub); $str_last_host = gmp_strval($last_host); $last_last_host = gmp_strval(gmp_sub($last_host, 1)); } // Validate that the subnet IP & netmask combo are valid together. $ip2 = str_pad(substr($ip1, 0, $cidr), $padding, '0'); $ip1 = ip_mangle($ip1, $fmt); $ip2 = ip_mangle($ip2, $fmt); if ($ip1 != $ip2) { $self['error'] = "ERROR => Invalid subnet specified - did you mean: {$ip2}/{$cidr}?"; return array(6, $self['error'] . "\n"); } // If our IP or netmask changed we need to make sure that // we won't abandon any host interfaces. // We also need to verify that the new boundaries are valid and // don't interefere with any other subnets. if ($check_boundaries == 1) { // *** Check to see if the new subnet overlaps any existing ONA subnets *** // // I convert the IP address to dotted format when calling ona_find_subnet() // because it saves it from doing a few unnecessary sql queries. // Look for overlaps like this (where new subnet address starts inside an existing subnet): // [ -- new subnet -- ] // [ -- old subnet --] list($status, $rows, $record) = ona_find_subnet(ip_mangle($options['set_ip'], 'dotted')); if ($rows and $record['id'] != $subnet['id']) { $self['error'] = "ERROR => Subnet address conflict! New subnet starts inside an existing subnet."; return array(7, $self['error'] . "\n" . "ERROR => Conflicting subnet record ID: {$record['id']}\n"); } // Look for overlaps like this (where the new subnet ends inside an existing subnet): // [ -- new subnet -- ] // [ -- old subnet --] // Find last address of our subnet, and see if it's inside of any other subnet: list($status, $rows, $record) = ona_find_subnet(ip_mangle($str_last_host, 'dotted')); if ($rows and $record['id'] != $subnet['id']) { $self['error'] = "ERROR => Subnet address conflict! New subnet ends inside an existing subnet."; return array(8, $self['error'] . "\n" . "ERROR => Conflicting subnet record ID: {$record['id']}\n"); } // Look for overlaps like this (where the new subnet entirely overlaps an existing subnet): // [ -------- new subnet --------- ] // [ -- old subnet --] // // Do a cool SQL query to find all subnets whose start address is >= or <= the // new subnet base address. $where = "ip_addr >= {$options['set_ip']} AND ip_addr <= {$str_last_host}"; list($status, $rows, $record) = ona_get_subnet_record($where); if ($rows > 1 or $rows == 1 and $record['id'] != $subnet['id']) { $self['error'] = "ERROR => Subnet address conflict! New subnet would encompass an existing subnet."; return array(9, $self['error'] . "\n" . "ERROR => Conflicting subnet record ID: {$record['id']}\n"); } // Look for any hosts that are currently in our subnet that would be // abandoned if we were to make the proposed changes. // Look for hosts on either side of the new subnet boundaries: // [--- new subnet ---] // * ** * * <-- Hosts: the first and last host would be a problem! // [------- old subnet --------] // $where1 = "subnet_id = {$subnet['id']} AND ip_addr < {$first_host}"; $where2 = "subnet_id = {$subnet['id']} AND ip_addr > {$last_last_host}"; list($status, $rows1, $record) = ona_get_interface_record($where1); list($status, $rows2, $record) = ona_get_interface_record($where2); if ($rows1 or $rows2) { $num = $rows1 + $rows2; $self['error'] = "ERROR => Changes would abandon {$num} hosts in an unallocated ip space"; return array(10, $self['error'] . "\n"); } // Look for any dhcp pools that are currently in our subnet that would be // abandoned if we were to make the proposed changes. // Look for existin pools with start/end values outside of new subnet range // [--- new subnet ---] // [--cur pool--] // [------- old subnet --------] // $where1 = "subnet_id = {$subnet['id']} AND ip_addr_start < {$options['set_ip']}"; $where2 = "subnet_id = {$subnet['id']} AND ip_addr_end > {$str_last_host}"; list($status, $rows1, $record) = ona_get_dhcp_pool_record($where1); list($status, $rows2, $record) = ona_get_dhcp_pool_record($where2); if ($rows1 or $rows2) { $num = $rows1 + $rows2; $self['error'] = "ERROR => Changes would abandon a DHCP pool in an unallocated ip space, adjust pool sizes first"; return array(10, $self['error'] . "\n"); } } // // Define the fields we're updating // // This variable will contain the updated info we'll insert into the DB $SET = array(); $SET['ip_addr'] = $options['set_ip']; $SET['ip_mask'] = $options['set_netmask']; // Set options['set_security_level']? // Sanitize "security_level" option if (array_key_exists('set_security_level', $options)) { $options['set_security_level'] = sanitize_security_level($options['set_security_level']); if ($options['set_security_level'] == -1) { return array(11, $self['error'] . "\n"); } $SET['lvl'] = $options['set_security_level']; } // Set options['set_name']? if ($options['set_name']) { // BUSINESS RULE: We require subnet names to be in upper case and spaces are converted to -'s. $options['set_name'] = trim($options['set_name']); $options['set_name'] = preg_replace('/\\s+/', '-', $options['set_name']); $options['set_name'] = strtoupper($options['set_name']); // Make sure there's not another subnet with this name list($status, $rows, $tmp) = ona_get_subnet_record(array('name' => $options['set_name'])); if ($status or $rows > 1 or $rows == 1 and $tmp['id'] != $subnet['id']) { $self['error'] = "ERROR => That name is already used by another subnet!"; return array(12, $self['error'] . "\n"); } $SET['name'] = $options['set_name']; } // Set options['set_type']? if ($options['set_type']) { // Find the type from $options[type] list($status, $rows, $subnet_type) = ona_find_subnet_type($options['set_type']); if ($status or $rows != 1) { $self['error'] = "ERROR => Invalid subnet type specified!"; return array(13, $self['error'] . "\n"); } printmsg("Subnet type selected: {$subnet_type['display_name']} ({$subnet_type['short_name']})", 1); $SET['subnet_type_id'] = $subnet_type['id']; } // Set options['set_vlan']? if (array_key_exists('set_vlan', $options) or $options['campus']) { if (!$options['set_vlan']) { $SET['vlan_id'] = ''; } else { // Find the VLAN ID from $options[set_vlan] and $options[campus] list($status, $rows, $vlan) = ona_find_vlan($options['set_vlan'], $options['campus']); if ($status or $rows != 1) { $self['error'] = "ERROR => The vlan/campus pair specified is invalid!"; return array(15, $self['error'] . "\n"); } printmsg("VLAN selected: {$vlan['name']} in {$vlan['vlan_campus_name']} campus", 1); $SET['vlan_id'] = $vlan['id']; } } // Update the subnet record list($status, $rows) = db_update_record($onadb, 'subnets', array('id' => $subnet['id']), $SET); if ($status or !$rows) { return array(16, $self['error'] . "\n"); } // Load the updated record for display list($status, $rows, $subnet) = ona_get_subnet_record(array('id' => $subnet['id'])); // Return the (human-readable) success notice $text = format_array($SET); $self['error'] = "INFO => Subnet UPDATED"; return array(0, $self['error'] . ":\n{$text}\n"); }
function custom_attribute_display($options = "") { // The important globals global $conf, $self, $onadb; $text_array = array(); // Version - UPDATE on every edit! $version = '1.02'; printmsg("DEBUG => custom_attribute_display({$options}) called", 3); // Parse incoming options string to an array $options = parse_options($options); // Return the usage summary if we need to if ($options['help'] or !$options['host'] and !$options['id'] and !$options['subnet'] and !$options['vlan']) { // NOTE: Help message lines should not exceed 80 characters for proper display on a console $self['error'] = 'ERROR => Insufficient parameters'; return array(1, <<<EOM custom_attribute_display-v{$version} Display the custom attribute specified or attributes for a host Synopsis: custom_attribute_display Where: id=ID custom attribute ID OR host=ID or NAME[.DOMAIN] display custom attributes for specified host OR subnet=ID or NAME display custom attributes for specified subnet OR vlan=NAME display custom attributes for specified VLAN Optional: type=ID or NAME If you specify a type and a host or subnet you will only get back a 1 or a 0 indicating that that type is set or not set for the host or subnet EOM ); } // if a type was set, check if it is associated with the host or subnet and return 1 or 0 if ($options['type']) { $field = is_numeric($options['type']) ? 'id' : 'name'; list($status, $rows, $catype) = ona_get_custom_attribute_type_record(array($field => $options['type'])); // error if we cant find the type specified if (!$catype['id']) { $self['error'] = "ERROR => The custom attribute type specified, {$options['type']}, does not exist!"; return array(5, $self['error']); } $where['custom_attribute_type_id'] = $catype['id']; } // Search for the host first if ($options['host']) { list($status, $rows, $host) = ona_find_host($options['host']); // Error if the host doesn't exist if (!$host['id']) { $self['error'] = "ERROR => The host specified, {$options['host']}, does not exist!"; return array(2, $self['error']); } else { $where['table_id_ref'] = $host['id']; $where['table_name_ref'] = 'hosts'; list($status, $rows, $cas) = db_get_records($onadb, 'custom_attributes', $where); } $anchor = 'host'; $desc = $host['fqdn']; } // Search for subnet if ($options['subnet']) { list($status, $rows, $subnet) = ona_find_subnet($options['subnet']); // Error if the record doesn't exist if (!$subnet['id']) { $self['error'] = "ERROR => The subnet specified, {$options['subnet']}, does not exist!"; return array(3, $self['error']); } else { $where['table_id_ref'] = $subnet['id']; $where['table_name_ref'] = 'subnets'; list($status, $rows, $cas) = db_get_records($onadb, 'custom_attributes', $where); } $anchor = 'subnet'; $desc = $subnet['description']; } // Search for vlan if ($options['vlan']) { list($status, $rows, $vlan) = ona_find_vlan($options['vlan']); // Error if the record doesn't exist if (!$vlan['id']) { $self['error'] = "ERROR => The VLAN specified, {$options['vlan']}, does not exist!"; return array(3, $self['error']); } else { $where['table_id_ref'] = $vlan['id']; $where['table_name_ref'] = 'vlans'; list($status, $rows, $cas) = db_get_records($onadb, 'custom_attributes', $where); } $anchor = 'vlan'; $desc = $vlan['description']; } // Now find the ID of the record, returns a specific record only if ($options['id']) { list($status, $rows, $ca) = ona_get_custom_attribute_record(array('id' => $options['id'])); if (!$ca['id']) { $self['error'] = "ERROR => The custom attribute specified, {$options['id']}, is invalid!"; return array(4, $self['error']); } $text_array = $ca; $text .= "CUSTOM ATTRIBUTE ENTRY RECORD ({$ca['id']})\n"; $text .= format_array($ca); } elseif ($options['type']) { // If we requested type, now is the time to return a response if it is found associated. if ($cas[0]) { $text .= '1'; $text_array['has_attribute'] = 'Y'; } else { $text .= '0'; $text_array['has_attribute'] = 'N'; } } else { // Build text to return $text .= strtoupper($anchor) . " CUSTOM ATTRIBUTE RECORDS ({$desc})\n"; // Display the record(s) $i = 0; do { $text .= "\nASSOCIATED CUSTOM ATTRIBUTE ENTRY RECORD ({$i} of {$rows})\n"; $text .= format_array($cas[$i]); list($status, $carows, $ca) = ona_get_custom_attribute_type_record(array('id' => $cas[$i]['custom_attribute_type_id'])); $text_array[$ca['name']] = $cas[$i]['value']; $i++; } while ($i < $rows); } // change the output format if other than default if ($options['format'] == 'json') { $text = $text_array; } if ($options['format'] == 'yaml') { $text = $text_array; } // Return the success notice return array(0, $text); }
function ws_editor($window_name, $form = '') { global $conf, $self, $onadb; global $font_family, $color, $style, $images; $window = array(); // Check permissions if (!auth('custom_attribute_del')) { $response = new xajaxResponse(); $response->addScript("alert('Permission denied!');"); return $response->getXML(); } // If an array in a string was provided, build the array and store it in $form $form = parse_options_string($form); // If $form is a number, it's a record id- so we transform $form into an array if ($form['id']) { list($status, $rows, $ca) = ona_get_custom_attribute_record(array('id' => $form['id'])); $window['title'] = "Edit Custom Attribute"; } else { $window['title'] = "Add Custom Attribute"; } // Load the subnet record and associated info. if (is_numeric($form['subnet_id'])) { list($status, $rows, $subnet) = ona_get_subnet_record(array('id' => $form['subnet_id'])); // Setup a title description for this edit type $window['edit_type'] = "Subnet"; $window['edit_type_value'] = $subnet['name']; } // If they are adding a new CA entry they will usually pass a host_id in if (is_numeric($form['host_id'])) { list($status, $rows, $host) = ona_find_host($form['host_id']); // Setup a title description for this edit type $window['edit_type'] = "Host"; $window['edit_type_value'] = $host['fqdn']; } if (is_numeric($form['vlan_id'])) { list($status, $rows, $vlan) = ona_find_vlan($form['vlan_id']); // Setup a title description for this edit type $window['edit_type'] = "Vlan"; $window['edit_type_value'] = $vlan['name']; } // Escape data for display in html foreach (array_keys((array) $subnet) as $key) { $subnet[$key] = htmlentities($subnet[$key], ENT_QUOTES, $conf['php_charset']); } foreach (array_keys((array) $host) as $key) { $host[$key] = htmlentities($host[$key], ENT_QUOTES, $conf['php_charset']); } // Build dhcp option list list($status, $rows, $catypes) = db_get_records($onadb, 'custom_attribute_types', 'id >= 1', 'name'); $ca_type_list = ''; foreach ($catypes as $record) { $selected = ""; if ($record['id'] == $ca['custom_attribute_type_id']) { $selected = "SELECTED=\"selected\""; } if ($record['id']) { $ca_type_list .= "<option {$selected} value=\"{$record['id']}\">{$record['name']}</option>\n"; } } // Javascript to run after the window is built $window['js'] = <<<EOL /* Put a minimize icon in the title bar */ el('{$window_name}_title_r').innerHTML = ' <a onClick="toggle_window(\\'{$window_name}\\');" title="Minimize window" style="cursor: pointer;"><img src="{$images}/icon_minimize.gif" border="0" /></a>' + el('{$window_name}_title_r').innerHTML; /* Put a help icon in the title bar */ el('{$window_name}_title_r').innerHTML = ' <a href="{$_ENV['help_url']}{$window_name}" target="null" title="Help" style="cursor: pointer;"><img src="{$images}/silk/help.png" border="0" /></a>' + el('{$window_name}_title_r').innerHTML; el('{$window_name}_form').onsubmit = function() { return false; }; EOL; // Define the window's inner html $window['html'] = <<<EOL <!-- Custom Attribute Edit Form --> <form id="{$window_name}_form" onSubmit="return false;"> <input type="hidden" name="host" value="{$host['id']}"> <input type="hidden" name="subnet" value="{$subnet['id']}"> <input type="hidden" name="vlan" value="{$vlan['id']}"> <input type="hidden" name="id" value="{$ca['id']}"> <input type="hidden" name="js" value="{$form['js']}"> <table cellspacing="0" border="0" cellpadding="0" style="background-color: {$color['window_content_bg']}; padding-left: 20px; padding-right: 20px; padding-top: 5px; padding-bottom: 5px;"> <!-- Custom Attribute RECORD --> <tr> <td align="left" nowrap="true"><b><u>CA Record</u></b> </td> <td class="padding" align="left" width="100%"> </td> </tr> <tr> <td align="right" nowrap="true"> {$window['edit_type']}: </td> <td class="padding" align="left" width="100%"> {$window['edit_type_value']} </td> </tr> <tr> <td class="input_required" align="right" nowrap="true"> Type </td> <td class="padding" align="left" width="100%"> <select id="type" name="type" class="edit" accesskey="t"> {$ca_type_list} </select> </td> </tr> <tr> <td class="input_required" align="right" nowrap="true"> Value </td> <td class="padding" align="left" width="100%"> <textarea name="value" alt="Value" class="edit" rows="5" cols="25" >{$ca['value']}</textarea> </td> </tr> <tr> <td align="right" valign="top" nowrap="true"> </td> <td class="padding" align="right" width="100%"> <input type="hidden" name="overwrite" value="{$overwrite}"> <input class="edit" type="button" name="cancel" value="Cancel" onClick="removeElement('{$window_name}');"> <input class="edit" type="button" name="submit" value="Save" accesskey=" " onClick="xajax_window_submit('{$window_name}', xajax.getFormValues('{$window_name}_form'), 'save');" > </td> </tr> </table> </form> EOL; return window_open($window_name, $window); }