swreg.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <?php
  2. #-
  3. # Copyright (c) 2011-2015 Joe Clarke <jclarke@cisco.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. # 1. Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in the
  13. # documentation and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. # SUCH DAMAGE.
  26. #
  27. #
  28. include_once '../db.inc.php';
  29. include_once 'swreg.inc.php';
  30. include_once '../swreg_creds.inc.php';
  31. require_once 'MDB2.php';
  32. require_once 'Log.php';
  33. $dsn = "mysql://$db_user:$db_pass@$db_host/$db_name";
  34. $options = array('result_buffering', false);
  35. $dbh = MDB2::factory($dsn, $options);
  36. if (PEAR::isError($dbh)) {
  37. die($dbh->getMessage());
  38. }
  39. $dbh->setFetchMode(MDB2_FETCHMODE_ASSOC);
  40. $logger = Log::singleton('file', LOGFILE, TOOL_NAME . ' : Switch Registrar');
  41. if ($logger === FALSE) {
  42. die("Failed to open logfile.\n");
  43. }
  44. $mask = Log::UPTO(LOG_LEVEL);
  45. $logger->setMask($mask);
  46. $pid = $_GET['pid'];
  47. $sn = $_GET['sn'];
  48. $version = $_GET['version'];
  49. $num_ports = $_GET['num_ports'];
  50. header('Content-type: text/plain');
  51. if (!isset($pid) || !isset($sn) || !isset($version) || !isset($num_ports)) {
  52. echo "ERROR: Invalid request!\r\n";
  53. $logger->emerg("Invalid request from " . $_SERVER['REMOTE_ADDR'] . " pid = '$pid', sn = '$sn', version = '$version', num_ports = '$num_ports'");
  54. exit(1);
  55. }
  56. $logger->debug("Received request from $sn: pid = $pid, version = $version, num_ports = $num_ports");
  57. $image = NULL;
  58. $config = NULL;
  59. $found_pid = NULL;
  60. $not_configed = "ERROR: Tool not properly configured.\r\n";
  61. foreach ($ZTP_PIDS as $zpid) {
  62. if (preg_match("/$zpid/", $pid)) {
  63. if (!isset($IMG_VERS[$zpid])) {
  64. echo $not_configed;
  65. $logger->emerg("\$IMG_VERS[$zpid] is not defined in swreg.inc.php!");
  66. exit(1);
  67. }
  68. if ($version != $IMG_VERS[$zpid]) {
  69. if (!isset($IMG_FILES[$zpid])) {
  70. echo $not_configed;
  71. $logger->emerg("\$IMG_FILES[$zpid] is not defined in swreg.inc.php!");
  72. exit(1);
  73. }
  74. $image = $IMG_FILES[$zpid];
  75. }
  76. if (!isset($EEM_CONFIG_FILES[$zpid])) {
  77. echo $not_configed;
  78. $logger->emerg("\$EEM_CONFIG_FILES[$zpid] is not defined in swreg.inc.php!");
  79. exit(1);
  80. }
  81. $eem_tmpl = $EEM_CONFIG_FILES[$zpid];
  82. if (!isset($START_PORTS[$zpid])) {
  83. echo $not_configed;
  84. $logger->emerg("\$START_PORTS[$zpid] is not defined in swreg.inc.php!");
  85. exit(1);
  86. }
  87. $start_port = $START_PORTS[$zpid];
  88. if (!isset($PORT_TYPES[$zpid])) {
  89. echo $not_configed;
  90. $logger->emerg("\$PORT_TYPES[$zpid] is not defined in swreg.inc.php!");
  91. exit(1);
  92. }
  93. $port_type = $PORT_TYPES[$zpid];
  94. $found_pid = $zpid;
  95. }
  96. }
  97. if ($found_pid === NULL) {
  98. $logger->crit("Request from unknown PID: $pid");
  99. echo "ERROR: Unknown PID: $pid\r\n";
  100. exit(1);
  101. }
  102. $sql = 'SELECT assigned_switch, max_ports, checked_out FROM DEVICE_MAP WHERE serial_number = ?';
  103. $sth = $dbh->prepare($sql);
  104. if (PEAR::isError($sth)) {
  105. echo "ERROR: Failed to prepare query '$sql': " . $sth->getUserInfo() . "\r\n";
  106. $logger->crit("Failed to prepare query '$sql': " . $sth->getUserInfo());
  107. exit(1);
  108. }
  109. $res = $sth->execute(array($sn));
  110. $sth->free();
  111. if (PEAR::isError($res)) {
  112. echo "ERROR: Failed to execute query '$sql' with parameter '$sn': " . $res->getUserInfo() . "\r\n";
  113. $logger->crit("Failed to execute query '$sql' with parameter '$sn': " . $res->getUserInfo());
  114. exit(1);
  115. }
  116. $row = $res->fetchRow();
  117. $max_ports = $row['max_ports'];
  118. if ($row['checked_out'] == 0) {
  119. echo "ERROR: Switch has not yet been provisioned via the web\r\n";
  120. $logger->crit("Switch $sn ({$_SERVER['REMOTE_ADDR']}) has not yet been provisioned via the web");
  121. exit(1);
  122. }
  123. if ($max_ports > $num_ports) {
  124. echo "ERROR: Switch has been provisioned for $max_ports but this physical switch only has $num_ports\r\n";
  125. $logger->crit("Switch $sn has been provisioned for $max_ports but this physical switch only has $num_ports");
  126. exit(1);
  127. }
  128. $sql = 'SELECT s.name AS hostname, s.location AS snmp_loc, s.is_idf AS is_idf, a.address AS ip, a.router AS gw, a.mask AS mask, a.mgmt_vlan AS mgmt_vlan, a.location AS location FROM SWITCHES s, ADDRESSES a WHERE s.name = ? AND s.ip_address = a.address';
  129. $sth = $dbh->prepare($sql);
  130. if (PEAR::isError($sth)) {
  131. echo "ERROR: Failed to prepare query '$sql': " . $sth->getUserInfo() . "\r\n";
  132. $logger->crit("Failed to prepare query '$sql': " . $sth->getUserInfo());
  133. exit(1);
  134. }
  135. $res = $sth->execute(array($row['assigned_switch']));
  136. $sth->free();
  137. if (PEAR::isError($res)) {
  138. echo "ERROR: Failed to execute query '$sql' with parameter '{$row['assigned_switch']}': " . $res->getUserInfo() . "\r\n";
  139. $logger->crit("Failed to execute query '$sql' with parameter '{$row['assigned_switch']}': " . $res->getUserInfo());
  140. exit(1);
  141. }
  142. $row = $res->fetchRow();
  143. $port_contents = "interface range {$port_type}{$start_port} - $max_ports\n";
  144. if (file_exists(PORT_TMPL_DIR . '/devices/' . $row['hostname'] . '-ports.tmpl')) {
  145. $port_contents = file_get_contents(PORT_TMPL_DIR . '/devices/' . $row['hostname'] . '-ports.tmpl');
  146. } else {
  147. if (file_exists(PORT_TMPL_DIR . '/ports.tmpl')) {
  148. $port_contents .= file_get_contents(PORT_TMPL_DIR . '/ports.tmpl');
  149. }
  150. if (file_exists(PORT_TMPL_DIR . '/' . $found_pid . '/ports.tmpl')) {
  151. $port_contents .= file_get_contents(PORT_TMPL_DIR . '/' . $found_pid . '/ports.tmpl');
  152. }
  153. if (file_exists(PORT_TMPL_DIR . '/DYNAMIC/ports.tmpl')) {
  154. $port_contents .= file_get_contents(PORT_TMPL_DIR . '/DYNAMIC/ports.tmpl');
  155. }
  156. if (file_exists(PORT_TMPL_DIR . '/DYNAMIC/' . $found_pid . '/ports.tmpl')) {
  157. $port_contents .= file_get_contents(PORT_TMPL_DIR . '/DYNAMIC/' . $found_pid . '/ports.tmpl');
  158. }
  159. }
  160. $snmp_loc = $row['snmp_loc'];
  161. if (!$snmp_loc || $snmp_loc == '') {
  162. $snmp_loc = $row['location'];
  163. }
  164. $ew_keywords = preg_replace("/\s/", '_', $snmp_loc);
  165. $ew_role = 'ACCESS-SWITCH';
  166. if ($row['is_idf'] == 1) {
  167. $ew_role = 'IDF-SWITCH';
  168. }
  169. $contents = "";
  170. if (file_exists(DEVICE_TMPL_DIR . "/device.tmpl")) {
  171. $contents .= file_get_contents(DEVICE_TMPL_DIR . "/device.tmpl");
  172. }
  173. if (file_exists(DEVICE_TMPL_DIR . '/' . $found_pid . '/device.tmpl')) {
  174. $contents .= file_get_contents(DEVICE_TMPL_DIR . '/' . $found_pid . '/device.tmpl');
  175. }
  176. if (file_exists(DEVICE_TMPL_DIR . '/actions/actions.tmpl')) {
  177. $contents .= file_get_contents(DEVICE_TMPL_DIR . '/actions/actions.tmpl');
  178. }
  179. if (file_exists(DEVICE_TMPL_DIR . '/actions/' . $found_pid . '/actions.tmpl')) {
  180. $contents .= file_get_contents(DEVICE_TMPL_DIR . '/actions/' . $found_pid . '/actions.tmpl');
  181. }
  182. $contents .= "end\n";
  183. $contents = str_replace("%%PORT_CONFIG%%", $port_contents, $contents);
  184. $contents = str_replace("%%MGMT_VLAN%%", $row['mgmt_vlan'], $contents);
  185. $contents = str_replace("%%HOSTNAME%%", $row['hostname'], $contents);
  186. $contents = str_replace("%%EW_DOMAIN%%", $row['location'], $contents);
  187. $contents = str_replace("%%EW_KEYWORDS%%", $ew_keywords, $contents);
  188. $contents = str_replace("%%EW_ROLE%%", $ew_role, $contents);
  189. $contents = str_replace("%%VTP_DOMAIN%%", $row['location'], $contents);
  190. $contents = str_replace("%%MGMT_IP%%", $row['ip'], $contents);
  191. $contents = str_replace("%%MGMT_MASK%%", $row['mask'], $contents);
  192. $contents = str_replace("%%MGMT_GW%%", $row['gw'], $contents);
  193. $contents = str_replace("%%SNMP_LOCATION%%", $snmp_loc, $contents);
  194. $contents = str_replace("%%START_PORT%%", $start_port, $contents);
  195. $contents = str_replace("%%MAX_PORT%%", $max_ports, $contents);
  196. # XXX: TODO
  197. $contents = str_replace("%%STACK_CONFIG%%", "!", $contents);
  198. # Replace creds
  199. $contents = str_replace("%%ADMIN_SECRET%%", ADMIN_SECRET, $contents);
  200. $contents = str_replace("%%TACACS_KEY%%", TACACS_KEY, $contents);
  201. $contents = str_replace("%%EW_SHARED_SECRET%%", EW_SHARED_SECRET, $contents);
  202. $contents = str_replace("%%EW_MGMT_SHARED_SECRET%%", EW_MGMT_SHARED_SECRET, $contents);
  203. $contents = str_replace("%%SNMPV3_USER%%", SNMPV3_USER, $contents);
  204. $contents = str_replace("%%SNMPV3_PASS%%", SNMPV3_PASS, $contents);
  205. $vlan_contents = file_get_contents(VLAN_TMPL_DIR . "/" . strtolower($row['location']) . "-vlan.tmpl");
  206. $contents = str_replace("%%VLAN_TMPL%%", $vlan_contents, $contents);
  207. $eem_contents = file_get_contents(TFTPBOOT . '/' . $eem_tmpl);
  208. $contents = str_replace("%%EEM_CONFIG%%", $eem_contents, $contents);
  209. if (isset($VLAN_OVERRIDES) && isset($VLAN_OVERRIDES[$row['location']])) {
  210. foreach ($VLAN_OVERRIDES[$row['location']] as $vn => $vi) {
  211. $VLANS[$vn] = $vi;
  212. }
  213. }
  214. foreach ($VLANS as $vn => $vi) {
  215. $vname = strtoupper($vn);
  216. $vname = str_replace(' ', '_', $vname);
  217. $macro = '%%' . $vname . '_VLAN%%';
  218. $contents = str_replace($macro, $vi, $contents);
  219. }
  220. $custom_macros = array();
  221. if (isset($CUSTOM_MACROS)) {
  222. foreach ($CUSTOM_MACROS as $macro => $mv) {
  223. $custom_macros[$macro] = $mv;
  224. }
  225. }
  226. if (isset($MDF_OVERRIDES) && isset($MDF_OVERRIDES[$row['location']])) {
  227. foreach ($MDF_OVERRIDES[$row['locations']] as $macro => $mv) {
  228. $custom_macros[$macro] = $mv;
  229. }
  230. }
  231. foreach ($custom_macros as $macro => $mv) {
  232. $contents = str_replace("%%$macro%%", $mv, $contents);
  233. }
  234. umask(0022);
  235. $fd = @fopen(DEVICE_CONFIG_DIR . '/' . $row['hostname'] . "-config.txt", "w");
  236. fwrite($fd, $contents);
  237. fclose($fd);
  238. $fd = @fopen(DEVICE_TMP_DIR . '/' . $row['hostname'] . "-config.txt", "w");
  239. fclose($fd);
  240. chmod(DEVICE_TMP_DIR . '/' . $row['hostname'] . "-config.txt", 0666);
  241. echo "Config: {$row['hostname']}-config.txt\r\n";
  242. if ($image !== NULL) {
  243. echo "Image: $image\r\n";
  244. }
  245. $logger->info("Successfully provisioned switch $sn ($pid) {$row['hostname']}");
  246. $dbh->disconnect();
  247. $logger->close();
  248. ?>