You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

templates.inc.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <?php
  2. /* Poweradmin, a friendly web-based admin tool for PowerDNS.
  3. * See <http://www.poweradmin.org> for more details.
  4. *
  5. * Copyright 2007-2009 Rejo Zenger <rejo@zenger.nl>
  6. * Copyright 2010-2014 Poweradmin Development Team
  7. * <http://www.poweradmin.org/credits.html>
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * Template functions
  24. *
  25. * @package Poweradmin
  26. * @copyright 2007-2010 Rejo Zenger <rejo@zenger.nl>
  27. * @copyright 2010-2014 Poweradmin Development Team
  28. * @license http://opensource.org/licenses/GPL-3.0 GPL
  29. */
  30. /** Get a list of all available zone templates
  31. *
  32. * @param int $userid User ID
  33. *
  34. * @return mixed[] array of zone templates [id,name,descr]
  35. */
  36. function get_list_zone_templ($userid) {
  37. global $db;
  38. $query = "SELECT * FROM zone_templ "
  39. . "WHERE owner = '" . $userid . "' "
  40. . "ORDER BY name";
  41. $result = $db->query($query);
  42. if (PEAR::isError($result)) {
  43. error("Not all tables available in database, please make sure all upgrade/install proceedures were followed");
  44. return false;
  45. }
  46. $zone_templ_list = array();
  47. while ($zone_templ = $result->fetchRow()) {
  48. $zone_templ_list[] = array(
  49. "id" => $zone_templ['id'],
  50. "name" => $zone_templ['name'],
  51. "descr" => $zone_templ['descr']
  52. );
  53. }
  54. return $zone_templ_list;
  55. }
  56. /** Add a zone template
  57. *
  58. * @param mixed[] $details zone template details
  59. * @param $userid User ID that owns template
  60. *
  61. * @return boolean true on success, false otherwise
  62. */
  63. function add_zone_templ($details, $userid) {
  64. global $db;
  65. $zone_name_exists = zone_templ_name_exists($details['templ_name']);
  66. if (!(verify_permission('zone_master_add'))) {
  67. error(ERR_PERM_ADD_ZONE_TEMPL);
  68. return false;
  69. } elseif ($zone_name_exists != '0') {
  70. error(ERR_ZONE_TEMPL_EXIST);
  71. } else {
  72. $query = "INSERT INTO zone_templ (name, descr, owner)
  73. VALUES ("
  74. . $db->quote($details['templ_name'], 'text') . ", "
  75. . $db->quote($details['templ_descr'], 'text') . ", "
  76. . $db->quote($userid, 'integer') . ")";
  77. $result = $db->query($query);
  78. if (PEAR::isError($result)) {
  79. error($result->getMessage());
  80. return false;
  81. }
  82. return true;
  83. }
  84. }
  85. /** Get name and description of template based on template ID
  86. *
  87. * @param int $zone_templ_id Zone template ID
  88. *
  89. * @return mixed[] zone template details
  90. */
  91. function get_zone_templ_details($zone_templ_id) {
  92. global $db;
  93. $query = "SELECT *"
  94. . " FROM zone_templ"
  95. . " WHERE id = " . $db->quote($zone_templ_id, 'integer');
  96. $result = $db->query($query);
  97. if (PEAR::isError($result)) {
  98. error($result->getMessage());
  99. return false;
  100. }
  101. $details = $result->fetchRow();
  102. return $details;
  103. }
  104. /** Delete a zone template
  105. *
  106. * @param int $zone_templ_id Zone template ID
  107. *
  108. * @return boolean true on success, false otherwise
  109. */
  110. function delete_zone_templ($zone_templ_id) {
  111. global $db;
  112. if (!(verify_permission('zone_master_add'))) {
  113. error(ERR_PERM_DEL_ZONE_TEMPL);
  114. return false;
  115. } else {
  116. // Delete the zone template
  117. $query = "DELETE FROM zone_templ"
  118. . " WHERE id = " . $db->quote($zone_templ_id, 'integer');
  119. $result = $db->query($query);
  120. if (PEAR::isError($result)) {
  121. error($result->getMessage());
  122. return false;
  123. }
  124. // Delete the zone template records
  125. $query = "DELETE FROM zone_templ_records"
  126. . " WHERE zone_templ_id = " . $db->quote($zone_templ_id, 'integer');
  127. $result = $db->query($query);
  128. if (PEAR::isError($result)) {
  129. error($result->getMessage());
  130. return false;
  131. }
  132. // Delete references to zone template
  133. $query = "DELETE FROM records_zone_templ"
  134. . " WHERE zone_templ_id = " . $db->quote($zone_templ_id, 'integer');
  135. $result = $db->query($query);
  136. if (PEAR::isError($result)) {
  137. error($result->getMessage());
  138. return false;
  139. }
  140. return true;
  141. }
  142. }
  143. /** Delete all zone templates for specific user
  144. *
  145. * @param $userid User ID
  146. *
  147. * @return boolean true on success, false otherwise
  148. */
  149. function delete_zone_templ_userid($userid) {
  150. global $db;
  151. if (!(verify_permission('zone_master_add'))) {
  152. error(ERR_PERM_DEL_ZONE_TEMPL);
  153. return false;
  154. } else {
  155. $query = "DELETE FROM zone_templ"
  156. . " WHERE owner = " . $db->quote($userid, 'integer');
  157. $result = $db->query($query);
  158. if (PEAR::isError($result)) {
  159. error($result->getMessage());
  160. return false;
  161. }
  162. return true;
  163. }
  164. }
  165. /** Count zone template records
  166. *
  167. * @param int $zone_templ_id Zone template ID
  168. *
  169. * @return boolean true on success, false otherwise
  170. */
  171. function count_zone_templ_records($zone_templ_id) {
  172. global $db;
  173. $query = "SELECT COUNT(id) FROM zone_templ_records WHERE zone_templ_id = " . $db->quote($zone_templ_id, 'integer');
  174. $record_count = $db->queryOne($query);
  175. if (PEAR::isError($record_count)) {
  176. error($record_count->getMessage());
  177. return false;
  178. }
  179. return $record_count;
  180. }
  181. /** Check if zone template exist
  182. *
  183. * @param int $zone_templ_id Zone template ID
  184. *
  185. * @return boolean true on success, false otherwise
  186. */
  187. function zone_templ_id_exists($zone_templ_id) {
  188. global $db;
  189. $query = "SELECT COUNT(id) FROM zone_templ WHERE id = " . $db->quote($zone_templ_id, 'integer');
  190. $count = $db->queryOne($query);
  191. if (PEAR::isError($count)) {
  192. error($count->getMessage());
  193. return false;
  194. }
  195. return $count;
  196. }
  197. /** Get a zone template record from an id
  198. *
  199. * Retrieve all fields of the record and send it back to the function caller.
  200. *
  201. * @param int $id zone template record id
  202. *
  203. * @return mixed[] zone template record
  204. * [id,zone_templ_id,name,type,content,ttl,prio] or -1 if nothing is found
  205. */
  206. function get_zone_templ_record_from_id($id) {
  207. global $db;
  208. if (is_numeric($id)) {
  209. $result = $db->queryRow("SELECT id, zone_templ_id, name, type, content, ttl, prio FROM zone_templ_records WHERE id=" . $db->quote($id, 'integer'));
  210. if ($result) {
  211. $ret = array(
  212. "id" => $result["id"],
  213. "zone_templ_id" => $result["zone_templ_id"],
  214. "name" => $result["name"],
  215. "type" => $result["type"],
  216. "content" => $result["content"],
  217. "ttl" => $result["ttl"],
  218. "prio" => $result["prio"],
  219. );
  220. return $ret;
  221. } else {
  222. return -1;
  223. }
  224. } else {
  225. error(sprintf(ERR_INV_ARG, "get_zone_templ_record_from_id"));
  226. }
  227. }
  228. /** Get all zone template records from a zone template id
  229. *
  230. * Retrieve all fields of the records and send it back to the function caller.
  231. *
  232. * @param int $id zone template ID
  233. * @param int $rowstart Starting row (default=0)
  234. * @param int $rowamount Number of rows per query (default=999999)
  235. * @param string $sortby Column to sort by (default='name')
  236. *
  237. * @return mixed[] zone template records numerically indexed
  238. * [id,zone_templd_id,name,type,content,ttl,pro] or -1 if nothing is found
  239. */
  240. function get_zone_templ_records($id, $rowstart = 0, $rowamount = 999999, $sortby = 'name') {
  241. global $db;
  242. if (is_numeric($id)) {
  243. $db->setLimit($rowamount, $rowstart);
  244. $result = $db->query("SELECT id FROM zone_templ_records WHERE zone_templ_id=" . $db->quote($id, 'integer') . " ORDER BY " . $sortby);
  245. $ret[] = array();
  246. $retcount = 0;
  247. while ($r = $result->fetchRow()) {
  248. // Call get_record_from_id for each row.
  249. $ret[$retcount] = get_zone_templ_record_from_id($r["id"]);
  250. $retcount++;
  251. }
  252. return ($retcount > 0 ? $ret : -1);
  253. } else {
  254. error(sprintf(ERR_INV_ARG, "get_zone_templ_records"));
  255. }
  256. }
  257. /** Add a record for a zone template
  258. *
  259. * This function validates and if correct it inserts it into the database.
  260. * TODO: actual validation?
  261. *
  262. * @param int $zone_templ_id zone template ID
  263. * @param string $name name part of record
  264. * @param string $type record type
  265. * @param string $content record content
  266. * @param int $ttl TTL
  267. * @param int $prio Priority
  268. *
  269. * @return boolean true if succesful, false otherwise
  270. */
  271. function add_zone_templ_record($zone_templ_id, $name, $type, $content, $ttl, $prio) {
  272. global $db;
  273. if (!(verify_permission('zone_master_add'))) {
  274. error(ERR_PERM_ADD_RECORD);
  275. return false;
  276. } else {
  277. if ($content == '') {
  278. error(ERR_DNS_CONTENT);
  279. return false;
  280. }
  281. if ($name != '') {
  282. if ($type == "SPF") {
  283. $content = $db->quote(stripslashes('\"' . $content . '\"'), 'text');
  284. } else {
  285. $content = $db->quote($content, 'text');
  286. }
  287. $query = "INSERT INTO zone_templ_records (zone_templ_id, name, type, content, ttl, prio) VALUES ("
  288. . $db->quote($zone_templ_id, 'integer') . ","
  289. . $db->quote($name, 'text') . ","
  290. . $db->quote($type, 'text') . ","
  291. . $content . ","
  292. . $db->quote($ttl, 'integer') . ","
  293. . $db->quote($prio, 'integer') . ")";
  294. $result = $db->query($query);
  295. if (PEAR::isError($result)) {
  296. error($result->getMessage());
  297. return false;
  298. }
  299. return true;
  300. } else {
  301. error(ERR_DNS_HOSTNAME);
  302. return false;
  303. }
  304. }
  305. }
  306. /** Modify zone template reocrd
  307. *
  308. * Edit a record for a zone template.
  309. * This function validates it if correct it inserts it into the database.
  310. *
  311. * @param mixed[] $record zone record array
  312. *
  313. * @return boolean true on success, false otherwise
  314. */
  315. function edit_zone_templ_record($record) {
  316. global $db;
  317. if (!(verify_permission('zone_master_add'))) {
  318. error(ERR_PERM_EDIT_RECORD);
  319. return false;
  320. } else {
  321. if ("" != $record['name']) {
  322. if ($record['type'] == "SPF") {
  323. $content = $db->quote(stripslashes('\"' . $record['content'] . '\"'), 'text');
  324. } else {
  325. $content = $db->quote($record['content'], 'text');
  326. }
  327. $query = "UPDATE zone_templ_records
  328. SET name=" . $db->quote($record['name'], 'text') . ",
  329. type=" . $db->quote($record['type'], 'text') . ",
  330. content=" . $content . ",
  331. ttl=" . $db->quote($record['ttl'], 'integer') . ",
  332. prio=" . $db->quote(isset($record['prio']) ? $record['prio'] : 0, 'integer') . "
  333. WHERE id=" . $db->quote($record['rid'], 'integer');
  334. $result = $db->query($query);
  335. if (PEAR::isError($result)) {
  336. error($result->getMessage());
  337. return false;
  338. }
  339. return true;
  340. } else {
  341. error(ERR_DNS_HOSTNAME);
  342. return false;
  343. }
  344. }
  345. }
  346. /** Delete a record for a zone template by a given id
  347. *
  348. * @param int $rid template record id
  349. *
  350. * @return boolean true on success, false otherwise
  351. */
  352. function delete_zone_templ_record($rid) {
  353. global $db;
  354. if (!(verify_permission('zone_master_add'))) {
  355. error(ERR_PERM_DEL_RECORD);
  356. return false;
  357. } else {
  358. $query = "DELETE FROM zone_templ_records WHERE id = " . $db->quote($rid, 'integer');
  359. $result = $db->query($query);
  360. if (PEAR::isError($result)) {
  361. error($result->getMessage());
  362. return false;
  363. }
  364. return true;
  365. }
  366. }
  367. /** Check if the session user is the owner for the zone template
  368. *
  369. * @param int $zone_templ_id zone template id
  370. * @param int $userid user id
  371. *
  372. * @return boolean true on success, false otherwise
  373. */
  374. function get_zone_templ_is_owner($zone_templ_id, $userid) {
  375. global $db;
  376. $query = "SELECT owner FROM zone_templ WHERE id = " . $db->quote($zone_templ_id, 'integer');
  377. $result = $db->queryOne($query);
  378. if (PEAR::isError($result)) {
  379. error($result->getMessage());
  380. return false;
  381. }
  382. if ($result == $userid) {
  383. return true;
  384. } else {
  385. return false;
  386. }
  387. }
  388. /** Add a zone template from zone / another template
  389. *
  390. * @param string $template_name template name
  391. * @param string $description description
  392. * @param int $userid user id
  393. * @param mixed[] $records array of zone records
  394. * @param string $domain domain to substitute with '[ZONE]' (optional) [default=null]
  395. *
  396. * @return boolean true on success, false otherwise
  397. */
  398. function add_zone_templ_save_as($template_name, $description, $userid, $records, $domain = null) {
  399. global $db;
  400. global $db_layer;
  401. global $db_type;
  402. if (!(verify_permission('zone_master_add'))) {
  403. error(ERR_PERM_ADD_ZONE_TEMPL);
  404. return false;
  405. } else {
  406. $result = $db->beginTransaction();
  407. $query = "INSERT INTO zone_templ (name, descr, owner)
  408. VALUES ("
  409. . $db->quote($template_name, 'text') . ", "
  410. . $db->quote($description, 'text') . ", "
  411. . $db->quote($userid, 'integer') . ")";
  412. $result = $db->exec($query);
  413. if ($db_layer == 'MDB2' && ($db_type == 'mysql' || $db_type == 'pgsql')) {
  414. $zone_templ_id = $db->lastInsertId('zone_templ', 'id');
  415. } else if ($db_layer == 'PDO' && $db_type == 'pgsql') {
  416. $zone_templ_id = $db->lastInsertId('zone_templ_id_seq');
  417. } else {
  418. $zone_templ_id = $db->lastInsertId();
  419. }
  420. $owner = get_zone_templ_is_owner($zone_templ_id, $_SESSION['userid']);
  421. foreach ($records as $record) {
  422. if ($record['type'] == "SPF") {
  423. $content = $db->quote(stripslashes('\"' . $record['content'] . '\"'), 'text');
  424. } else {
  425. $content = $db->quote($record['content'], 'text');
  426. }
  427. $name = $domain ? preg_replace('/' . $domain . '/', '[ZONE]', $record['name']) : $record['name'];
  428. $content = $domain ? preg_replace('/' . $domain . '/', '[ZONE]', $content) : $content;
  429. $query2 = "INSERT INTO zone_templ_records (zone_templ_id, name, type, content, ttl, prio) VALUES ("
  430. . $db->quote($zone_templ_id, 'integer') . ","
  431. . $db->quote($name, 'text') . ","
  432. . $db->quote($record['type'], 'text') . ","
  433. . $content . ","
  434. . $db->quote($record['ttl'], 'integer') . ","
  435. . $db->quote(isset($record['prio']) ? $record['prio'] : 0, 'integer') . ")";
  436. $result = $db->exec($query2);
  437. }
  438. if (PEAR::isError($result)) {
  439. $result = $db->rollback();
  440. } else {
  441. $result = $db->commit();
  442. }
  443. }
  444. return true;
  445. }
  446. /** Get list of all zones using template
  447. *
  448. * @param int $zone_templ_id zone template id
  449. * @param int $userid user id
  450. *
  451. * @return mixed[] array of zones [id,name,type,count_records]
  452. */
  453. function get_list_zone_use_templ($zone_templ_id, $userid) {
  454. global $db;
  455. if (verify_permission('zone_content_edit_others')) {
  456. $perm_edit = "all";
  457. } elseif (verify_permission('zone_content_edit_own')) {
  458. $perm_edit = "own";
  459. } else {
  460. $perm_edit = "none";
  461. }
  462. $sql_add = '';
  463. if ($perm_edit != "all") {
  464. $sql_add = " AND zones.domain_id = domains.id
  465. AND zones.owner = " . $db->quote($userid, 'integer');
  466. }
  467. $query = "SELECT domains.id,
  468. domains.name,
  469. domains.type,
  470. Record_Count.count_records
  471. FROM domains
  472. LEFT JOIN zones ON domains.id=zones.domain_id
  473. LEFT JOIN (
  474. SELECT COUNT(domain_id) AS count_records, domain_id FROM records GROUP BY domain_id
  475. ) Record_Count ON Record_Count.domain_id=domains.id
  476. WHERE 1=1" . $sql_add . "
  477. AND zone_templ_id = " . $db->quote($zone_templ_id, 'integer') . "
  478. GROUP BY domains.name, domains.id, domains.type, Record_Count.count_records";
  479. $result = $db->query($query);
  480. if (PEAR::isError($result)) {
  481. error("Not all tables available in database, please make sure all upgrade/install proceedures were followed");
  482. return false;
  483. }
  484. $zone_list = array();
  485. while ($zone = $result->fetchRow()) {
  486. $zone_list[] = array(
  487. "id" => $zone['id'],
  488. "name" => $zone['name'],
  489. "type" => $zone['type'],
  490. "count_records" => $zone['count_records']
  491. );
  492. }
  493. return $zone_list;
  494. }
  495. /** Modify zone template
  496. *
  497. * @param mixed[] $details array of new zone template details
  498. * @param int $zone_templ_id zone template id
  499. *
  500. * @return boolean true on success, false otherwise
  501. */
  502. function edit_zone_templ($details, $zone_templ_id) {
  503. global $db;
  504. $zone_name_exists = zone_templ_name_exists($details['templ_name'], $zone_templ_id);
  505. if (!(verify_permission('zone_master_add'))) {
  506. error(ERR_PERM_ADD_ZONE_TEMPL);
  507. return false;
  508. } elseif ($zone_name_exists != '0') {
  509. error(ERR_ZONE_TEMPL_EXIST);
  510. return false;
  511. } else {
  512. $query = "UPDATE zone_templ
  513. SET name=" . $db->quote($details['templ_name'], 'text') . ",
  514. descr=" . $db->quote($details['templ_descr'], 'text') . "
  515. WHERE id=" . $db->quote($zone_templ_id, 'integer');
  516. $result = $db->query($query);
  517. if (PEAR::isError($result)) {
  518. error($result->getMessage());
  519. return false;
  520. }
  521. return true;
  522. }
  523. }
  524. /** Check if zone template name exists
  525. *
  526. * @param string $zone_templ_name zone template name
  527. * @param int $zone_templ_id zone template id (optional) [default=null]
  528. *
  529. * @return int number of matching templates
  530. */
  531. function zone_templ_name_exists($zone_templ_name, $zone_templ_id = null) {
  532. global $db;
  533. $sql_add = '';
  534. if ($zone_templ_id) {
  535. $sql_add = " AND id != " . $db->quote($zone_templ_id, 'integer');
  536. }
  537. $query = "SELECT COUNT(id) FROM zone_templ WHERE name = " . $db->quote($zone_templ_name, 'text') . "" . $sql_add;
  538. $count = $db->queryOne($query);
  539. if (PEAR::isError($count)) {
  540. error($count->getMessage());
  541. return false;
  542. }
  543. return $count;
  544. }
  545. /** Parse string and substitute domain and serial
  546. *
  547. * @param string $val string to parse containing tokens '[ZONE]' and '[SERIAL]'
  548. * @param string $domain domain to subsitute for '[ZONE]'
  549. *
  550. * @return string interpolated/parsed string
  551. */
  552. function parse_template_value($val, $domain) {
  553. $serial = date("Ymd");
  554. $serial .= "00";
  555. $val = str_replace('[ZONE]', $domain, $val);
  556. $val = str_replace('[SERIAL]', $serial, $val);
  557. return $val;
  558. }
  559. /** Add relation between zone record and template
  560. *
  561. * @param type $db DB link
  562. * @param type $domain_id Domain id
  563. * @param type $record_id Record id
  564. * @param type $zone_templ_id Zone template id
  565. */
  566. function add_record_relation_to_templ($db, $domain_id, $record_id, $zone_templ_id) {
  567. $query = "INSERT INTO records_zone_templ (domain_id, record_id, zone_templ_id) VALUES ("
  568. . $db->quote($domain_id, 'integer') . ","
  569. . $db->quote($record_id, 'integer') . ","
  570. . $db->quote($zone_templ_id, 'integer') . ")";
  571. $db->query($query);
  572. }
  573. /** Check if given relation exists
  574. *
  575. * @param type $db
  576. * @param type $domain_id
  577. * @param type $record_id
  578. * @param type $zone_templ_id
  579. * @return boolean true on success, false on failure
  580. */
  581. function record_relation_to_templ_exists($db, $domain_id, $record_id, $zone_templ_id) {
  582. $query = "SELECT COUNT(*) FROM records_zone_templ WHERE domain_id = " . $db->quote($domain_id, 'integer') .
  583. " AND record_id = " . $db->quote($record_id, 'integer') . " AND zone_templ_id = " . $db->quote($zone_templ_id, 'integer');
  584. $count = $db->queryOne($query);
  585. if ($count == 0) {
  586. return false;
  587. }
  588. return true;
  589. }