Compare commits

..

125 commits
v1.0 ... master

Author SHA1 Message Date
Tuxis B.V.
7a18c00a24
Merge pull request #206 from bartvanhalder/master
Add support to load templates from json files
2025-03-11 09:17:49 +01:00
Tuxis B.V.
2ea8bff800
Merge pull request #207 from PowerDNS/docker-bookworm
update Dockerfile to Debian bookworm
2025-03-11 09:16:24 +01:00
Peter van Dijk
12d3d33c36 update Dockerfile to Debian bookworm 2025-03-10 15:20:29 +01:00
Tuxis B.V.
6c565719d9
Merge pull request #189 from stecklars/master
INCEPTION-INCREMENT is not a valid option for soa_edit_api
2024-08-19 14:41:51 +02:00
Tuxis B.V.
fe4120e2a7
Merge pull request #205 from deividasraila/feat/default_login_credentials
Default login crediantials in config
2024-08-19 14:40:55 +02:00
Bart van Halder
8e1d0035d3
[.gitignore] ignore json files in templates.d/ 2024-07-25 15:38:00 +02:00
Bart van Halder
a3ba9ed45e
Add a way to load templates from json files 2024-07-25 15:32:03 +02:00
Deividas Raila
3b69fcf770 Default login crediantials in config 2024-05-07 18:11:07 +03:00
Tuxis B.V
65d58cfd92
Merge pull request #204 from WilliamDEdwards/fix/ipv6-api-ip
Place brackets around IPv6 address
2024-04-29 21:39:17 +02:00
William Edwards
c8f28c5c3e Place brackets around IPv6 address
Without this, using an IPv6 address as $apiip is not possible, because cURL requires brackets.
2024-04-29 20:48:04 +02:00
Tuxis B.V
39050cd015
Merge pull request #203 from WilliamDEdwards/fix/make-clone-admin-only
Make cloning admin-only, check zones returned by formzonelist
2024-04-17 12:21:46 +02:00
William Edwards
e8d028ba75 Make cloning admin-only, check zones returned by formzonelist
Cloning was meant to be an admin-only functionality. However, this was not fully implemented: when `allowzoneadd = true`, the user could clone zones, even when not an admin. This is not necessarily a problem. But in this case, it is. Because the endpoint that is used to get zones to clone (`formzonelist`), did not check whether those zones belong to the current user. In other words: when `allowzoneadd = true` and the user is not an admin, that user is able to see *all zones* under 'Clone a zone' button -> 'Source domain' dropdown.

This commit fixes that, by letting `formzonelist` return only zones belonging to the user, and showing the 'Clone a zone' button only when the user is an admin.
2024-04-17 12:18:06 +02:00
Tuxis B.V
a4aa3c35cf
Merge pull request #202 from WilliamDEdwards/fix/add-missing-return
Add missing return to Comment::export
2024-01-23 17:13:29 +01:00
William Edwards
e5a121f24b Add missing return to Comment::export
Without this return, RRSet::exportComments returns an array of `null`, which causes PowerDNS to return `Key 'content' not present or not a String`.
2024-01-23 16:21:18 +01:00
Tuxis B.V
76d70251bb
Merge pull request #201 from zydronium/master
Deprecated: Creation of dynamic properties is deprecated in PHP8.2
2023-06-20 15:46:30 +02:00
Jelle Luteijn
b7ef64db18
Update Zone.php 2023-06-20 14:24:17 +02:00
Jelle Luteijn
758a021ca2
Update Zone.php 2023-06-20 14:22:36 +02:00
Jelle Luteijn
cae4e4ff93
Update Zone.php 2023-06-20 14:14:45 +02:00
Jelle Luteijn
7c50964633
Update ApiHandler.php 2023-06-20 14:13:08 +02:00
Jelle Luteijn
d59da92f37
Update PdnsApi.php
Creation of dynamic property PdnsAPI::$http is deprecated
2023-06-20 14:12:30 +02:00
Jelle Luteijn
607ecbd9f2
forgot $ 2023-06-20 14:06:52 +02:00
Jelle Luteijn
c327e23859
Update session.inc.php
Passing null to parameter #2 ($value) of type string is deprecated
2023-06-20 14:03:20 +02:00
Jelle Luteijn
e38fa1e120
Update ApiHandler.php
Creation of dynamic property ApiHandler::$headers is deprecated
2023-06-20 13:57:08 +02:00
Jelle Luteijn
b8e3261180
Update session.inc.php
Using ${var} in strings is deprecated, use {$var} instead
2023-06-20 13:45:10 +02:00
Tuxis B.V
947ec4a67d
Merge pull request #195 from tuxis-ie/check-authdb-docroot
Simply check if authdb is in the docroot.
2020-12-23 13:14:48 +01:00
Mark Schouten
d414f239a8 Simply check if authdb is in the docroot. If so, just blocklogin with a nice message. 2020-12-23 13:11:40 +01:00
Tuxis B.V
8efcfbd597
Merge pull request #194 from tuxis-ie/template-ns-records
If a template contains NS-records, do not try to add them again. They were already added while creating the zone.
2020-12-23 11:48:42 +01:00
Mark Schouten
5c6c9e1847 If a template contains NS-records, do not try to add them again. They were already added while creating the zone. 2020-12-23 11:45:58 +01:00
Tuxis B.V
888e7bad42
Merge pull request #193 from margau/master
AuthDB Download Check improvements
2020-11-26 09:47:28 +01:00
Marvin Gaube
82db64595c authdb check: Use relative, not absolute path 2020-03-01 20:18:15 +01:00
Marvin Gaube
6ba23a85b8 Only run authdb check when user is logged in 2020-03-01 20:15:14 +01:00
Tuxis B.V
059c679193
Merge pull request #192 from jbrunemann/master
#188 only replace basename when there is actually something to replace
2020-01-22 11:43:33 +01:00
Jan Brunemann
8586816c47 #188 only replace basename when there is actually something to replace 2020-01-22 11:33:27 +01:00
Lars-Sören Steck
de278c9ad7
INCEPTION-INCREMENT is not a valid option for soa_edit_api
INCEPTION-INCREMENT is not a valid option for soa_edit_api, see:
https://doc.powerdns.com/authoritative/domainmetadata.html#soa-edit-api

-> "These rules are the same as the SOA-EDIT-DNSUPDATE rules."
--> https://doc.powerdns.com/authoritative/dnsupdate.html#dnsupdate-soa-serial-updates
---> There is no "INCEPTION-INCREMENT" Setting.

Since 4.2 this is more strictly checked by PowerDNS:
636301b9f1 (diff-fcc782f1cdc22f79be390c5d65da9050)

Before this, it would simply use the DEFAULT option, now it logs an error and doesn't increase the Serial.
2019-07-28 02:57:29 +02:00
Mark Schouten
371eb41787 Content must be canonical 2018-08-22 17:12:01 +02:00
Tuxis Internet Engineering V.O.F
c63dbba617
Merge pull request #183 from tuxis-ie/nice-authdb-error
Show a clear message instead of ERROR 500
2018-08-22 16:51:28 +02:00
Mark Schouten
9407c92a6a Show a clear message instead of ERROR 500 2018-08-22 16:51:07 +02:00
Tuxis Internet Engineering V.O.F
23b9fe2c54
Merge pull request #182 from tuxis-ie/margau-patch-1
Margau patch 1
2018-08-22 16:45:32 +02:00
Mark Schouten
523fc1849d Test if we can download the from the browser. Alert, annoyingly, that the user should fix this 2018-08-22 16:43:19 +02:00
Mark Schouten
3448ccf653 Merge branch 'patch-1' of https://github.com/margau/nsedit into margau-patch-1 2018-08-22 16:41:41 +02:00
Tuxis Internet Engineering V.O.F
e80aa0dca7
Merge pull request #181 from tuxis-ie/support-SMIMEA
Support SMIMEA fields, fixes and closes #174
2018-08-22 16:06:40 +02:00
Mark Schouten
92290bdf05 Support SMIMEA fields, fixes and closes #174 2018-08-22 16:05:48 +02:00
Tuxis Internet Engineering V.O.F
3facd3271f
Merge pull request #180 from tuxis-ie/fix-api-calls
Fix api calls
2018-08-22 15:54:32 +02:00
Mark Schouten
be647cc26a Do not insert 'localhost', we are autodetecting the API url 2018-08-22 15:39:11 +02:00
Mark Schouten
bf513b9ffd Assume that we have Pdns > 4.x 2018-08-22 15:21:26 +02:00
Tuxis Internet Engineering V.O.F
880508f585
Merge pull request #171 from margau/master
API issue with PDNS 4.1.1
2018-06-05 10:30:05 +02:00
margau
39cf7138ef
Update README.md 2018-04-17 19:41:33 +02:00
margau
e403e396bc
Update README.md 2018-04-17 19:37:38 +02:00
margau
96c67a8e8f
Added notice (see #172) 2018-04-17 19:33:58 +02:00
margau
805176648d Fixed from paulgiordanozethcon suggestion in https://github.com/tuxis-ie/nsedit/issues/162 2018-04-17 18:53:31 +02:00
Tuxis Internet Engineering V.O.F
ebd12ebeb2
Merge pull request #167 from zydronium/patch-1
Fixing Undefined index
2018-03-28 09:07:39 +02:00
Tuxis Internet Engineering V.O.F
1dedc3ae3f
Merge pull request #168 from hutchinsonnetworks/master
Docker: Move configuration to runtime rather than build time
2018-03-28 09:06:55 +02:00
Tuxis Internet Engineering V.O.F
77d7c50110
Merge pull request #169 from tuxis-ie/revert-166-master
Revert "notify pdns after zone update"
2018-03-28 09:05:28 +02:00
Tuxis Internet Engineering V.O.F
635441dbe0
Revert "notify pdns after zone update" 2018-03-28 09:05:09 +02:00
Tuxis Internet Engineering V.O.F
ed27b5e7d1
Merge pull request #166 from Rico29/master
notify pdns slaves after zone update
2018-03-28 09:03:11 +02:00
Harry Reeder
a2d7c21636 Move configuration to runtime rather than build time 2018-03-19 16:00:38 +00:00
Jelle Luteijn
4f013d4081
Fixing Undefined index
PHP Notice:  Undefined index: label in /var/www/nsedit/wwwroot/zones.php on line 325
2018-02-08 23:41:07 +01:00
root
d44b1a011f wrong syntax correction 2018-02-05 09:58:06 +01:00
root
6dc6df497e typo correction 2018-02-02 15:12:11 +01:00
root
cb234599b7 typo correction 2018-02-02 15:10:54 +01:00
root
03d9d88026 add "notifyafterupdate" flag 2018-02-02 14:58:10 +01:00
Tuxis Internet Engineering V.O.F
1dfd47ae70
Merge pull request #161 from tuxis-ie/fix-issue-160
Fix issue 160
2017-11-20 16:04:42 +01:00
Mark Schouten
c1c680217d Set zonekind of the new zone 2017-11-20 15:58:15 +01:00
Mark Schouten
374e03aa43 Add zone to database and fix ownership 2017-11-20 15:56:28 +01:00
Tuxis Internet Engineering V.O.F
877d433b92
Merge pull request #159 from jsoref/spelling
Spelling
2017-11-20 10:35:50 +01:00
Josh Soref
ac5304badb spelling: whether 2017-11-19 00:58:36 +00:00
Josh Soref
fd2a7cb7a5 spelling: nameserver 2017-11-17 09:23:49 +00:00
Josh Soref
c3bd9da355 spelling: configuration 2017-11-17 09:11:20 +00:00
Tuxis Internet Engineering V.O.F
0befe9e5ab Merge pull request #155 from maltris/master
Separated RUN-commands, changed a sed-command because the matching did not work
2017-10-05 11:29:53 +02:00
maltris
0c1183e716 Separated RUN-commands, changed a sed-command because the matching did not work 2017-08-14 10:22:04 +02:00
Tuxis Internet Engineering V.O.F
4b060c6430 Merge pull request #153 from webvanced/master
Added support for CNAME's to zone in templates
2017-08-07 10:32:40 +02:00
Mark Schouten
18fa97373e Add other ways of installation to the README 2017-08-07 10:30:52 +02:00
Daniel Eiland
1f2225cf6d Added support for CNAME's to zone in templates 2017-07-11 09:24:44 +02:00
Mark Schouten
382ca51db1 Allow ALIAS records. Closes #138 2017-04-28 13:37:22 +02:00
Mark Schouten
6be5f2f29c Fix updating the password, and store if we have local auth, we can't change passwords if we don't have local auth 2017-04-28 13:09:31 +02:00
Mark Schouten
f67fa04d85 This fixes the issues with the newer pdns, which suddenly includes the whole API url in the returned json.
Closes #145. In response to 4d4e536d52
2017-04-28 12:32:01 +02:00
Mark Schouten
9d27a140d7 Fix proto in logo url 2017-04-20 11:46:55 +02:00
Mark Schouten
4d4e536d52 Deduplicate the api-url 2017-04-20 11:45:33 +02:00
Tuxis Internet Engineering V.O.F
6fbd049941 Merge pull request #143 from tuxis-ie/caa-support
Implement CAA-records. Please note that pdns requires quotes around t…
2017-04-03 09:48:15 +02:00
Mark Schouten
0e63757d19 Implement CAA-records. Please note that pdns requires quotes around the third field: https://github.com/PowerDNS/pdns/issues/4937. Closes #141 2017-04-03 09:47:38 +02:00
Mark Schouten
5787659b07 Add this missing line, this may have broken editing of SPF/TXT records. Closes #140 2017-01-25 09:46:05 +01:00
Tuxis Internet Engineering V.O.F
b7d61f5778 Merge pull request #136 from krombel/master
fix switching of Views for non-admin-users (fix #135)
2016-11-21 10:15:03 +01:00
Krombel
a3affccacd fix switching of Views for non-admin-users (#135) 2016-11-19 02:50:09 +01:00
Mark Schouten
93c88cc196 If we get here, there is a value without dots... So add it 2016-11-18 17:11:22 +01:00
Mark Schouten
5c5f9f7abd Fix sorting 2016-11-18 17:07:49 +01:00
Mark Schouten
6737aa9b83 Fix matching on zonename, we were missing the . 2016-11-18 17:01:48 +01:00
Mark Schouten
ae00aa8ed9 Fix quoting of TXT and SPF records 2016-11-18 17:00:18 +01:00
Mark Schouten
42b247d5c0 Add missing types. Closes #130 2016-11-03 10:11:24 +01:00
Mark Schouten
41801a73f6 Try to set soa_edit_api, if it is not yet set 2016-10-25 12:14:07 +02:00
Mark Schouten
94e0d22bf2 If we don't have a soa_edit_api for this zone yet, set it to our default 2016-10-25 11:10:22 +02:00
Mark Schouten
77192d84b1 Don't close the database connection and make it global. Also, honour the account that is set in pdns, unless its empty 2016-10-19 17:28:16 +02:00
Mark Schouten
92ac4576ab An empty name is possible 2016-10-14 14:20:07 +02:00
Mark Schouten
b5d7fa8183 Don't forget the dot in between 2016-10-14 14:16:48 +02:00
Mark Schouten
83e8a0eda6 TRAILING DOTSS!!!11eleven!!11!&$W*&@*@!@#& 2016-10-14 14:14:17 +02:00
Mark Schouten
32f0456f21 Fix TXT-record quoting 2016-10-10 14:22:31 +02:00
Tuxis Internet Engineering V.O.F
b34d7ee2f1 Merge pull request #123 from richard-underwood/issue-122
Modified users jtable to use id & fixed user deletion.
2016-09-26 16:45:18 +02:00
Richard Underwood
083cb9429c Modified users jtable to use id & fixed user deletion. 2016-09-20 10:10:54 +01:00
Tuxis Internet Engineering V.O.F
e7713615a5 Merge pull request #120 from bjoe2k4/master 2016-09-19 12:04:51 +02:00
bjoe2k4
5d1f23c814 Update .gitignore 2016-09-17 15:27:29 +02:00
Tuxis Internet Engineering V.O.F
b16af25052 Merge pull request #108 from richard-underwood/issue-107
Ability to rotate and search logs
2016-09-13 11:10:22 +02:00
Richard Underwood
badebb9965 Clarified wording of rotation warning. 2016-08-26 11:59:49 +01:00
Richard Underwood
8d6e8ddf55 Removed delete button from logs table as the action wasn't implemented and would not be possible on rotated logs. 2016-08-26 11:45:30 +01:00
Richard Underwood
669c78a1db Merge remote-tracking branch 'origin/master' into issue-107 2016-08-26 10:54:04 +01:00
Tuxis Internet Engineering V.O.F
531f8a2609 Merge pull request #110 from richard-underwood/issue-109
PHP <= 5.4 fix for curl_reset
2016-08-26 11:50:48 +02:00
Richard Underwood
9d59441dd0 Check around curl_reset to prevent errors with PHP <=5.4 2016-08-26 10:11:52 +01:00
Richard Underwood
7c767b7769 Merge remote-tracking branch 'origin/master' into issue-107
Add test for pre-PHP 5.4 for pretty-printing logs

Conflicts:
	includes/misc.inc.php
2016-08-26 10:00:51 +01:00
Tuxis Internet Engineering V.O.F
6833f59400 Merge pull request #105 from tuxis-ie/fix-bug-104
Fix logging in cases we don't have a username yet. Also, log more stu…
2016-08-26 10:38:24 +02:00
Richard Underwood
2cb95a6959 UNRELATED CHANGE - put test around curl_reset to allow testing on PHP 5.4 2016-08-26 09:30:56 +01:00
Richard Underwood
befb891174 Changed Download logs to download the logs currently being shown, not always the current logs - note, doesn't filter first.
Removed "delete" case in logs.php
Moved logging check out of case statements to avoid duplication.
Changed wording of clear logs warning.
Pretty-print the JSON on log export - requires PHP 5.4.
2016-08-25 10:23:31 +01:00
Richard Underwood
ff8df5e5b2 Merge remote-tracking branch 'origin/master' into issue-107 2016-08-24 14:59:23 +01:00
Mark Schouten
43e4d53611 Fix CSS issues to eliminate whitespace with vertical menubar 2016-08-24 15:49:39 +02:00
Richard Underwood
9d8d909c18 Remove jtable_respond from the CLI script. 2016-08-24 14:38:03 +01:00
Richard Underwood
f081d96b0c Allow viewing of past logs.
Add a command-line PHP script for rotation in cron.
2016-08-24 14:19:52 +01:00
Richard Underwood
56c1789b30 Changed "Save logs" to "Download logs" for clarity.
Removed the rotate logs icon.
Updated warning text for clearing logs, if rotation is allowed.
2016-08-24 11:42:22 +01:00
Richard Underwood
d1b817443c Initial implementation of log rotation. 2016-08-24 11:32:43 +01:00
Tuxis Internet Engineering V.O.F
a8abca1121 Merge pull request #106 from richard-underwood/issue-90
Implemented logs and zone searching.
Closes: #90
2016-08-23 17:24:33 +02:00
Richard Underwood
708327ecd2 Match capitalisation on toolbar 2016-08-23 16:23:10 +01:00
Richard Underwood
dde58c798c Implemented logs and zone searching. 2016-08-23 15:56:41 +01:00
Mark Schouten
b91317046b Fix logging in cases we don't have a username yet. Also, log more stuff. Closes #104 2016-08-23 12:30:27 +02:00
Mark Schouten
4b5d4b02c9 Fix bug in Exception() and clearify the error message. Closes #100 2016-08-09 22:59:29 +02:00
Mark Schouten
b04b4dd864 Set ttl for the whole rrset if we update a record within that rrset. Might update other records as well, but that's as designed. Should fix #99 2016-08-08 19:13:47 +02:00
Tuxis Internet Engineering V.O.F
8cb9df7597 Merge pull request #98 from tuxis-ie/fix-add-user
emailaddress is a key, but we want to be able to use it upon create. …
2016-08-08 09:20:50 +02:00
Mark Schouten
b850510e5a emailaddress is a key, but we want to be able to use it upon create. Closes #97 2016-08-08 09:20:21 +02:00
Tuxis Internet Engineering V.O.F
d04a7ac8fe Merge pull request #96 from abcdmitry/patch-1 2016-08-05 23:33:32 +02:00
Dmitry Lukashin
44561faea4 Add notes about configuring PowerDNS 2016-08-06 00:30:54 +03:00
17 changed files with 743 additions and 170 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
includes/config.inc.php
nsedit.sublime*
etc
templates.d/*.json

View file

@ -1,38 +1,28 @@
FROM debian:jessie
FROM debian:bookworm
MAINTAINER Yury Evtikhov <yury@evtikhov.info>
#
# This Dockerfile is intended only for test/development use.
# It will be a really BAD idea to use it for production or public services.
#
ENV DEBIAN_FRONTEND noninteractive
#
# Please set the following variables before building:
#
ENV PDNSAPIPWD mypowerdnsapipassword
ENV PDNSAPIIP 192.168.1.2
ENV PDNSAPIPORT 8081
# Update and Upgrade system
RUN apt-get -y update && \
apt-get -y install curl git-core php5-cli php5-curl php5-json php5-sqlite && \
mkdir /app && \
git clone --recursive https://github.com/tuxis-ie/nsedit.git /app/nsedit && \
cp /app/nsedit/includes/config.inc.php-dist /app/nsedit/includes/config.inc.php && \
sed "s/\$apipass = ''/\$apipass = '$PDNSAPIPWD'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$apiip = ''/\$apiip = '$PDNSAPIIP'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$apiport = ''/\$apiport = '$PDNSAPIPORT'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$authdb = \"\.\.\/etc\/pdns\.users\.sqlite3\"/\$authdb = \"\/app\/pdns\.users\.sqlite3\"/" -i /app/nsedit/includes/config.inc.php
apt-get -y install curl git-core php8.2-cli php8.2-curl php8.2-sqlite3 && \
rm -rf /var/lib/apt/lists/*
RUN mkdir /app
RUN git clone --recursive https://github.com/tuxis-ie/nsedit.git /app/nsedit
RUN cp /app/nsedit/includes/config.inc.php-dist /app/nsedit/includes/config.inc.php
COPY docker-entrypoint.sh /app/nsedit/docker-entrypoint.sh
RUN chmod +x /app/nsedit/docker-entrypoint.sh
# Define working directory.
VOLUME /app/nsedit
WORKDIR /app/nsedit
EXPOSE 8080
ENTRYPOINT ["/usr/bin/php", "-S", "0.0.0.0:8080"]
CMD ["sh", "-c", "/app/nsedit/docker-entrypoint.sh"]
#
# Usage:

View file

@ -19,7 +19,7 @@ Features
User support
============
Multiple users are supported. A user can be an admin or a normal user. You can
configure wheter or not a normal user is allowed to add new zones.
configure whether or not a normal user is allowed to add new zones.
WeFact Login support
====================
@ -50,12 +50,35 @@ Installing
* Copy ```includes/config.inc.php-dist``` to ```includes/config.inc.php``` and edit config.inc.php to your needs.
* By default, nsedit writes its user database to ../etc/pdns.users.sqlite3. Be sure that your webserver can create that directory and write to it.
* By default, nsedit writes its user database to ../etc/pdns.users.sqlite3. Be sure that your webserver can create that directory and write to it. **Make sure the Webserver doesn't serve this file/folder to the public!**
* Visit http(s)://<url>/nsedit/ and login with admin/admin (Don't forget to update your password!)
Have fun ;)
Other methods of installation (Unsupported)
===========================================
* Baji Zsolt created a Suse image: https://susestudio.com/a/vvnMqa/powerdns-with-nsedit
* Yury Evtikhov created the Docker file: https://github.com/tuxis-ie/nsedit/blob/master/Dockerfile
Configuring PowerDNS
====================
Minimal configuration of PowerDNS for supporting nsedit has to include 3 directives:
```
webserver=yes
api=yes
api-key=SomeRandomString
```
Special note for Ubuntu Xenial Xerus 16.04 users:
Default `pdns` package included in Ubuntu repositories has the version of 4.0.0-alpha2 and *nsedit v1.0* doesn't work with it due to API incompatibility.
If your PowerDNS version is not the latest one, please consider adding PowerDNS repository to your system.
Detailed instructions for adding repository are available at http://repo.powerdns.com/
Screenshots
===========

View file

@ -15,6 +15,7 @@ body, html {
border: 1px solid #DDD;
font-family: 'Segoe UI Semilight','Open Sans',Verdana,Arial,Helvetica,sans-serif;
font-weight: 300;
float: left;
font-size: 14px;
line-height: 1.3;
width: 10%;

13
docker-entrypoint.sh Normal file
View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
[ -z "$PDNSAPIIP" ] && echo "Set PDNSAPIIP to your PowerDNS API IP/Hostname" && exit 1;
[ -z "$PDNSAPIPWD" ] && echo "Set PDNSAPIPWD to your PowerDNS API Password" && exit 1;
sed "s/\$apipass = ''/\$apipass = '$PDNSAPIPWD'/" -i /app/nsedit/includes/config.inc.php
sed "s/\$apiip = ''/\$apiip = '$PDNSAPIIP'/" -i /app/nsedit/includes/config.inc.php
if [[ $PDNSAPIPORT && ${PDNSAPIPORT-x} ]]
then
sed "s/\$apiport = '8081'/\$apiport = '$PDNSAPIPORT'/" -i /app/nsedit/includes/config.inc.php
fi
sed "s/\$authdb = \"\.\.\/etc\/pdns\.users\.sqlite3\"/\$authdb = \"\/app\/pdns\.users\.sqlite3\"/" -i /app/nsedit/includes/config.inc.php
exec /usr/bin/php -S 0.0.0.0:8080

View file

@ -3,6 +3,19 @@
include_once('includes/config.inc.php');
class ApiHandler {
public $headers;
public $hostname;
public $port;
public $auth;
public $proto;
public $sslverify;
public $curlh;
public $method;
public $content;
public $apiurl;
public $url;
public $json;
public function __construct() {
global $apiip, $apiport, $apipass, $apiproto, $apisslverify;
@ -29,22 +42,21 @@ class ApiHandler {
private function apiurl() {
$tmp = new ApiHandler();
$tmp->url = '/api';
$tmp->url = '/api/v1/servers/localhost';
$tmp->go();
if ($tmp->json[0]['version'] <= 1) {
$this->apiurl = $tmp->json[0]['url'];
} else {
throw new Exception("Unsupported API version");
}
$this->apiurl = $tmp->json["url"];
}
private function curlopts() {
$this->authheaders();
$this->addheader('Accept', 'application/json');
if(defined('curl_reset')) {
curl_reset($this->curlh);
} else {
$this->curlh = curl_init();
}
curl_setopt($this->curlh, CURLOPT_HTTPHEADER, Array());
curl_setopt($this->curlh, CURLOPT_RETURNTRANSFER, 1);
@ -61,7 +73,13 @@ class ApiHandler {
}
private function baseurl() {
return $this->proto.'://'.$this->hostname.':'.$this->port.$this->apiurl;
$ip = $this->hostname;
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$ip = sprintf('[%s]', $ip); // curl needs brackets for IPv6
}
return $this->proto.'://'.$ip.':'.$this->port.$this->apiurl;
}
private function go() {
@ -89,12 +107,6 @@ class ApiHandler {
curl_setopt($this->curlh, CURLOPT_URL, $this->baseurl().$this->url);
//print "Here we go:\n";
//print "Request: ".$this->method.' '.$this->baseurl().$this->url."\n";
//if ($this->content != '') {
// print "Content: ".$this->content."\n";
//}
$return = curl_exec($this->curlh);
$code = curl_getinfo($this->curlh, CURLINFO_HTTP_CODE);
$json = json_decode($return, 1);
@ -112,12 +124,11 @@ class ApiHandler {
}
public function call() {
if (substr($this->url, 0, 1) == '/') {
$this->apiurl();
} else {
$this->apiurl = '/';
if (substr($this->url, 0, 1) != '/') {
$this->url = '/'.$this->url;
}
$this->apiurl();
$this->url = str_replace($this->apiurl, '', $this->url);
$this->go();
}
}

View file

@ -3,6 +3,9 @@
include_once('ApiHandler.php');
class PdnsAPI {
public $http;
public function __construct() {
$this->http = new ApiHandler();
}
@ -11,7 +14,7 @@ class PdnsAPI {
$api = clone $this->http;
$api->method = 'GET';
if ($q) {
$api->url = "/servers/localhost/search-data?q=*".$q."*&max=25";
$api->url = "/search-data?q=*".$q."*&max=25";
$api->call();
$ret = Array();
$seen = Array();
@ -28,7 +31,7 @@ class PdnsAPI {
return $ret;
}
$api->url = "/servers/localhost/zones";
$api->url = "/zones";
$api->call();
return $api->json;
@ -37,7 +40,7 @@ class PdnsAPI {
public function loadzone($zoneid) {
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid";
$api->url = "/zones/$zoneid";
$api->call();
return $api->json;
@ -46,7 +49,7 @@ class PdnsAPI {
public function exportzone($zoneid) {
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid/export";
$api->url = "/zones/$zoneid/export";
$api->call();
return $api->json;
@ -64,7 +67,7 @@ class PdnsAPI {
if (!isset($zone['serial']) or gettype($zone['serial']) != 'integer') {
$api->method = 'POST';
$api->url = '/servers/localhost/zones';
$api->url = '/zones';
$api->content = json_encode($zonedata);
$api->call();
@ -88,7 +91,7 @@ class PdnsAPI {
public function deletezone($zoneid) {
$api = clone $this->http;
$api->method = 'DELETE';
$api->url = "/servers/localhost/zones/$zoneid";
$api->url = "/zones/$zoneid";
$api->call();
return $api->json;
@ -98,7 +101,7 @@ class PdnsAPI {
$ret = array();
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid/cryptokeys";
$api->url = "/zones/$zoneid/cryptokeys";
$api->call();

View file

@ -1,6 +1,21 @@
<?php
class Zone {
public $id;
public $name;
public $kind;
public $url;
public $serial;
public $dnssec;
public $soa_edit;
public $soa_edit_api;
public $keyinfo;
public $account;
public $zone;
public $nameservers;
public $rrsets;
public $masters;
public function __construct() {
$this->id = '';
$this->name = '';
@ -26,10 +41,10 @@ class Zone {
$this->setAccount($data['account']);
$this->setSerial($data['serial']);
$this->url = $data['url'];
if (isset($data['soa_edit']))
if (isset($data['soa_edit']) && $data['soa_edit'] != "")
$this->setSoaEdit($data['soa_edit']);
if (isset($data['soa_edit_api']))
$this->setSoaEditApi($data['soa_edit_api']);
if (isset($data['soa_edit_api']) && $data['soa_edit_api'] != "")
$this->setSoaEditApi($data['soa_edit_api'], True);
foreach ($data['masters'] as $master) {
$this->addMaster($master);
@ -76,7 +91,12 @@ class Zone {
$this->soa_edit = $soaedit;
}
public function setSoaEditApi($soaeditapi) {
public function setSoaEditApi($soaeditapi, $overwrite=False) {
if (isset($this->soa_edit_api) and $this->soa_edit_api != "") {
if ($overwrite === False) {
return False;
}
}
$this->soa_edit_api = $soaeditapi;
}
public function setName($name) {
@ -125,6 +145,7 @@ class Zone {
if ($rrset) {
$rrset->addRecord($content, $disabled, $setptr);
$rrset->setTtl($ttl);
} else {
$this->addRRSet($name, $type, $content, $disabled, $ttl, $setptr);
}
@ -180,8 +201,12 @@ class Zone {
$ret['nameservers'] = $this->nameservers;
$ret['kind'] = $this->kind;
$ret['name'] = $this->name;
if (isset($this->soa_edit) && $this->soa_edit != "") {
$ret['soa_edit'] = $this->soa_edit;
}
if (isset($this->soa_edit_api) && $this->soa_edit_api != "") {
$ret['soa_edit_api'] = $this->soa_edit_api;
}
if ($this->zone) {
$ret['zone'] = $this->zone;
return $ret;
@ -211,6 +236,13 @@ class Zone {
}
class RRSet {
public $name;
public $type;
public $ttl;
public $changetype;
public $records;
public $comments;
public function __construct($name = '', $type = '', $content = '', $disabled = FALSE, $ttl = 3600, $setptr = FALSE) {
$this->name = $name;
$this->type = $type;
@ -239,7 +271,7 @@ class RRSet {
public function addRecord($content, $disabled = FALSE, $setptr = FALSE) {
foreach ($this->records as $record) {
if ($record->content == $content) {
throw Exception("Record already exists");
throw new Exception($this->name."/".$this->type." has duplicate records.");
}
}
@ -296,6 +328,10 @@ class RRSet {
}
class Record {
public $content;
public $disabled;
public $setptr;
public function __construct($content, $disabled = FALSE, $setptr = FALSE) {
$this->content = $content;
$this->disabled = $disabled;
@ -316,6 +352,10 @@ class Record {
}
class Comment {
public $content;
public $account;
public $modified_at;
public function __construct($content, $account, $modified_at) {
$this->content = $content;
$this->account = $account;
@ -328,6 +368,8 @@ class Comment {
$ret['content'] = $this->content;
$ret['account'] = $this->account;
$ret['modified_at'] = $this->modified_at;
return $ret;
}
}

View file

@ -7,7 +7,12 @@ $apiproto = 'http'; # http | https
$apisslverify = FALSE; # Verify SSL Certificate if using https for apiproto
$allowzoneadd = FALSE; # Allow normal users to add zones
$logging = TRUE;
$allowclearlogs = TRUE; # Allow clearing of log entries
$allowrotatelogs = FALSE;# Allow rotation to text file on server
# Log directory - if allowrotatelogs is set, this is where the logs will
# be written. It must be writeable by the web server user.
$logsdirectory = "../etc";
# If you configure this, nsedit will try to authenticate via WeFact too.
# Debtors will be added to the sqlitedatabase with their crypted password.
@ -19,8 +24,13 @@ $logging = TRUE;
#$adminapiips = array();
#$adminapikey = 'thisshouldbequitealongstring,youknow';
# Location of user-database. Make sure its writeable and not served by the webserver!
$authdb = "../etc/pdns.users.sqlite3";
# Admin login and password at first start-up
$default_admin_username = "admin";
$default_admin_password = "admin";
# Set a random generated secret to enable auto-login and long living csrf tokens
// $secret = '...';
@ -33,13 +43,21 @@ $templates[] = array(
array(
'name' => '',
'type' => 'MX',
'content' => '200 mx2.tuxis.nl')
'content' => '200 mx2.tuxis.nl.'),
array(
'name' => '',
'type' => 'A',
'content' => '1.2.3.4'),
array(
'name' => 'www',
'type' => 'CNAME',
'content' => '[zonename]')
)
);
*/
$defaults['soa_edit'] = 'INCEPTION-INCREMENT';
$defaults['soa_edit_api'] = 'INCEPTION-INCREMENT';
$defaults['soa_edit_api'] = 'DEFAULT';
$defaults['defaulttype'] = 'Master'; # Choose between 'Native' or 'Master'
$defaults['ns'][0] = 'unconfigured.primaryns.'; # The value of the first NS-record
$defaults['ns'][1] = 'unconfigured.secondaryns.'; # The value of the second NS-record

View file

@ -35,7 +35,7 @@ if (isset($defaults['primaryns'])) {
}
if (!isset($logo) or empty($logo)) {
$logo = 'http://www.tuxis.nl/uploads/images/nsedit.png';
$logo = 'https://www.tuxis.nl/uploads/images/nsedit.png';
}
@ -59,13 +59,20 @@ if (function_exists('openssl_random_pseudo_bytes') === FALSE) {
$defaults['defaulttype'] = ucfirst(strtolower($defaults['defaulttype']));
if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) {
try {
if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) {
is_dir(dirname($authdb)) || mkdir(dirname($authdb));
$db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE);
$createsql = file_get_contents('includes/scheme.sql');
$db->exec($createsql);
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('admin', '".crypt("admin", '$6$'.$salt)."', 1)");
$default_admin_username = $default_admin_username ?? "admin";
$default_admin_password = $default_admin_password ?? "admin";
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('".$default_admin_username."', '".crypt($default_admin_password, '$6$'.$salt)."', 1)");
}
} catch (Exception $e) {
print("We have issues getting the authdb working: $e");
$blocklogin = TRUE;
}
function string_starts_with($string, $prefix)
@ -85,10 +92,12 @@ function string_ends_with($string, $suffix)
}
function get_db() {
global $authdb;
global $authdb, $db;
if (!isset($db)) {
$db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE);
$db->exec('PRAGMA foreign_keys = 1');
}
return $db;
}
@ -110,7 +119,6 @@ function get_user_info($u) {
$q->bindValue(1, $u);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
return $userinfo;
}
@ -125,10 +133,8 @@ function do_db_auth($u, $p) {
$q->bindValue(1, $u);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
if ($userinfo and $userinfo['password'] and (crypt($p, $userinfo['password']) === $userinfo['password'])) {
writelog('Succesful login.');
return TRUE;
}
@ -150,7 +156,6 @@ function add_user($username, $isadmin = FALSE, $password = '') {
$q->bindValue(2, $password, SQLITE3_TEXT);
$q->bindValue(3, (int)(bool) $isadmin, SQLITE3_INTEGER);
$ret = $q->execute();
$db->close();
if ($isadmin) {
writelog("Added user $username as admin.");
@ -160,7 +165,7 @@ function add_user($username, $isadmin = FALSE, $password = '') {
return $ret;
}
function update_user($username, $isadmin, $password) {
function update_user($id, $isadmin, $password) {
if ($password && !preg_match('/\$6\$/', $password)) {
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$password = crypt($password, '$6$'.$salt);
@ -168,33 +173,49 @@ function update_user($username, $isadmin, $password) {
$db = get_db();
$q = $db->prepare('SELECT * FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
$username = $userinfo['emailaddress'];
if ($password) {
$q = $db->prepare('UPDATE users SET isadmin = ?, password = ? WHERE emailaddress = ?');
$q = $db->prepare('UPDATE users SET isadmin = ?, password = ? WHERE id = ?');
$q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER);
$q->bindValue(2, $password, SQLITE3_TEXT);
$q->bindValue(3, $username, SQLITE3_TEXT);
$q->bindValue(3, $id, SQLITE3_INTEGER);
writelog("Updating password and/or settings for $username. Admin: ".(int)(bool)$isadmin);
} else {
$q = $db->prepare('UPDATE users SET isadmin = ? WHERE emailaddress = ?');
$q = $db->prepare('UPDATE users SET isadmin = ? WHERE id = ?');
$q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER);
$q->bindValue(2, $username, SQLITE3_TEXT);
$q->bindValue(2, $id, SQLITE3_INTEGER);
writelog("Updating settings for $username. Admin: ".(int)(bool)$isadmin);
}
$ret = $q->execute();
$db->close();
return $ret;
}
function delete_user($username) {
function delete_user($id) {
$db = get_db();
$q = $db->prepare('SELECT * FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
if($userinfo) {
$q = $db->prepare('DELETE FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
$db->close();
writelog("Deleted user $username.");
writelog("Deleted user " . $userinfo['emailaddress'] . ".");
return $ret;
} else {
return false;
}
}
function valid_user($name) {
@ -224,6 +245,8 @@ function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errorm
$jTableResult['RecordCount'] = count($records);
}
$db = get_db();
$db->close();
header('Content-Type: application/json');
print json_encode($jTableResult);
exit(0);
@ -232,6 +255,27 @@ function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errorm
function user_template_list() {
global $templates;
if (is_dir("templates.d")) {
if ($templdir=opendir("templates.d")) {
while ($entry = readdir($templdir)) {
if (!str_ends_with($entry, ".json")) {
continue;
}
$f=file_get_contents("templates.d/$entry");
if ($f === false) {
error_log("Error reading file templates.d/$entry", 0);
continue;
}
$t = json_decode($f, true);
if ($t === null) {
error_log("Error decoding templates.d/$entry", 0);
continue;
}
array_push($templates, $t);
}
}
}
$templatelist = array();
foreach ($templates as $template) {
if (is_adminuser()
@ -273,15 +317,70 @@ function clearlogs() {
$db = get_db();
$q = $db->query('DELETE FROM logs;');
$db->close();
writelog("Logtable truncated.");
}
function writelog($line) {
function rotatelogs() {
global $logging, $logsdirectory;
if ($logging !== TRUE)
return FALSE;
if(!is_dir($logsdirectory) || !is_writable($logsdirectory)) {
writelog("Logs directory cannot be written to.");
return FALSE;
}
date_default_timezone_set('UTC');
$filename = date("Y-m-d-His") . ".json";
$file = fopen($logsdirectory . "/" . $filename, "x");
if($file === FALSE) {
writelog("Can't create file for log rotation.");
return FALSE;
}
if(fwrite($file,json_encode(getlogs())) === FALSE) {
writelog("Can't write to file for log rotation.");
fclose($file);
return FALSE;
} else {
fclose($file);
clearlogs();
return $filename;
}
}
function listrotatedlogs() {
global $logging, $logsdirectory;
if ($logging !== TRUE)
return FALSE;
$list = scandir($logsdirectory,SCANDIR_SORT_DESCENDING);
if($list === FALSE) {
writelog("Logs directory cannot read.");
return FALSE;
}
$list=array_filter($list,
function ($val) {
return(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$val) == 1);
}
);
return $list;
}
function writelog($line, $user=False) {
global $logging;
if ($logging !== TRUE)
return;
if ($user === False) {
$user = get_sess_user();
}
try {
$db = get_db();
$q = $db->prepare('CREATE TABLE IF NOT EXISTS logs (
@ -292,10 +391,9 @@ function writelog($line) {
$ret = $q->execute();
$q = $db->prepare('INSERT INTO logs (user, log) VALUES (:user, :log)');
$q->bindValue(':user', get_sess_user(), SQLITE3_TEXT);
$q->bindValue(':user', $user, SQLITE3_TEXT);
$q->bindValue(':log', $line, SQLITE3_TEXT);
$q->execute();
$db->close();
} catch (Exception $e) {
return jtable_respond(null, 'error', $e->getMessage());
}

View file

@ -9,11 +9,13 @@ global $current_user;
$current_user = false;
// session startup
function _set_current_user($username, $is_admin = false, $has_csrf_token = false, $is_api = false) {
function _set_current_user($username, $userid, $localauth = true, $is_admin = false, $has_csrf_token = false, $is_api = false) {
global $current_user;
$current_user = array(
'username' => $username,
'id' => $userid,
'localauth' => $localauth,
'is_admin' => $is_admin,
'has_csrf_token' => $has_csrf_token,
'is_api' => $is_api,
@ -50,7 +52,7 @@ function _check_csrf_token($user) {
}
define('CSRF_TOKEN', $csrf_token);
header("X-CSRF-Token: ${csrf_token}");
header("X-CSRF-Token: {$csrf_token}");
}
function enc_secret($message) {
@ -120,13 +122,13 @@ function dec_secret($code) {
function _unset_cookie($name) {
$is_ssl = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
setcookie($name, null, -1, null, null, $is_ssl);
setcookie($name, "", -1, "", "", $is_ssl);
}
function _store_auto_login($value) {
$is_ssl = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
// set for 30 days
setcookie('NSEDIT_AUTOLOGIN', $value, time()+60*60*24*30, null, null, $is_ssl);
setcookie('NSEDIT_AUTOLOGIN', $value, time()+60*60*24*30, "", "", $is_ssl);
}
function try_login() {
@ -150,6 +152,7 @@ function _try_login($username, $password) {
global $wefactapiurl, $wefactapikey;
if (!valid_user($username)) {
writelog("Illegal username at login!", $username);
return false;
}
@ -158,6 +161,7 @@ function _try_login($username, $password) {
if (isset($wefactapiurl) && isset($wefactapikey)) {
$wefact = do_wefact_auth($username, $password);
if (false === $wefact ) {
writelog("Failed Wefact login!", $username);
return false;
}
if (-1 !== $wefact) {
@ -166,14 +170,16 @@ function _try_login($username, $password) {
}
if ($do_local_auth && !do_db_auth($username, $password)) {
writelog("Failed login!", $username);
return false;
}
$user = get_user_info($username);
if (!$user) {
writelog("Failed to find user!", $username);
return false;
} else {
_set_current_user($username, (bool) $user['isadmin']);
_set_current_user($username, $user['id'], (bool) $do_local_auth, (bool) $user['isadmin']);
if (session_id()) {
session_unset();
@ -183,6 +189,8 @@ function _try_login($username, $password) {
session_regenerate_id(true) or die('session failure: regenerated id failed');
session_unset();
$_SESSION['username'] = $username;
$_SESSION['localauth'] = $do_local_auth;
$_SESSION['userid'] = $user['id'];
# requires session:
_check_csrf_token($user);
@ -202,7 +210,7 @@ function _check_session() {
and $_POST['adminapikey'] === $adminapikey)
{
# Allow this request, fake that we're logged in as user.
return _set_current_user('admin', true, true, true);
return _set_current_user('admin', 1, false, true, true, true);
}
else
{
@ -218,7 +226,7 @@ function _check_session() {
session_destroy();
session_unset();
} else {
_set_current_user($_SESSION['username'], (bool) $user['isadmin']);
_set_current_user($_SESSION['username'], $_SESSION['userid'], (bool) $_SESSION['localauth'], (bool) $user['isadmin']);
_check_csrf_token($user);
return;
}
@ -277,6 +285,16 @@ function get_sess_user() {
return $current_user ? $current_user['username'] : null;
}
function get_sess_userid() {
global $current_user;
return $current_user ? $current_user['id'] : null;
}
function has_local_auth() {
global $current_user;
return $current_user ? $current_user['localauth'] : null;
}
function logout() {
@session_destroy();
@session_unset();

235
index.php
View file

@ -6,6 +6,12 @@ include_once('includes/misc.inc.php');
global $errormsg, $blocklogin;
$docroot = $_SERVER['DOCUMENT_ROOT'];
if (preg_match("@$docroot@", $authdb) == 1) {
$blocklogin = TRUE;
$errormsg = "You authdb is in your document root and probably downloadable. Please move it to a safe location!";
}
if (isset($_GET['logout']) or isset($_POST['logout'])) {
logout();
header("Location: index.php");
@ -20,7 +26,7 @@ if (!is_logged_in() and isset($_POST['formname']) and $_POST['formname'] === "lo
if (is_logged_in() and isset($_POST['formname']) and $_POST['formname'] === "changepwform") {
if (get_sess_user() == $_POST['username']) {
if (!update_user(get_sess_user(), is_adminuser(), $_POST['password'])) {
if (!update_user(get_sess_userid(), is_adminuser(), $_POST['password'])) {
$errormsg = "Unable to update password!\n";
}
} else {
@ -114,7 +120,45 @@ if ($blocklogin === TRUE) {
<div id="dnssecinfo">
</div>
<div id="clearlogs" style="display: none;">
Are you sure you want to clear all the logs? Maybe save them first?
Are you sure you want to clear the current logs? Maybe download them
first<?php if($allowrotatelogs) { ?>, or use "Rotate logs" to save
them on the server<?php } ?>?
</div>
<div id="rotatelogs" style="display: none;">
Are you sure you want to rotate the current logs?
</div>
<div id="searchlogs" style="display: none; text-align: right;">
<table border="0">
<tr><td>User:</td><td><input type="text" id ="searchlogs-user"><br></td></tr>
<tr><td>Log Entry:</td><td><input type="text" id ="searchlogs-entry"></td></tr>
</table>
</div>
<div id="searchzone" style="display: none; text-align: right;">
<table border="0">
<tr><td>Label:</td><td><input type="text" id ="searchzone-label"><br></td></tr>
<tr><td>Type:</td><td style="text-align: left;"><select id="searchzone-type">
<option value=""></option>
<option value="A">A</option>
<option value="AAAA">AAAA</option>
<option value="CERT">CERT</option>
<option value="CNAME">CNAME</option>
<option value="ALIAS">ALIAS</option>
<option value="LOC">LOC</option>
<option value="MX">MX</option>
<option value="NAPTR">NAPTR</option>
<option value="NS">NS</option>
<option value="PTR">PTR</option>
<option value="SOA">SOA</option>
<option value="SPF">SPF</option>
<option value="SRV">SRV</option>
<option value="SSHFP">SSHFP</option>
<option value="TLSA">TLSA</option>
<option value="CAA">CAA</option>
<option value="TXT">TXT</option>
<option value="SMIMEA">SMIMEA</option>
</select><br></td></tr>
<tr><td>Content:</td><td><input type="text" id ="searchzone-content"></td></tr>
</table>
</div>
<div id="menu" class="jtable-main-container <?php if ($menutype === 'horizontal') { ?>horizontal<?php } ?>">
<div class="jtable-title menu-title">
@ -137,9 +181,11 @@ if ($blocklogin === TRUE) {
}
?>
<div id="zones">
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
<div style="visibility: hidden;" id="ImportZone"></div>
<div style="visibility: hidden;" id="CloneZone"></div>
<?php if ($allowzoneadd === TRUE) { ?>
<div style="display: none;" id="ImportZone"></div>
<?php } ?>
<?php if (is_adminuser()) { ?>
<div style="display: none;" id="CloneZone"></div>
<?php } ?>
<div class="tables" id="MasterZones">
<div class="searchbar" id="searchbar">
@ -154,9 +200,25 @@ if ($blocklogin === TRUE) {
</div>
<div id="logs">
<div class="tables" id="Logs"></div>
<?php if($allowrotatelogs) { ?>
<br>Log entries being viewed:
<select id="logfile">
<option value="">(Current logs)</option>
<?php
$logfiles=listrotatedlogs();
if($logfiles !== FALSE) {
foreach ($logfiles as $filename) {
echo '<option value="' . $filename . '">' . str_replace(".json","",$filename) . "</option>\n";
}
}
?></select>
<?php } else { ?>
<input type="hidden" id="logfile" value="">
<?php } ?>
</div>
<?php } ?>
<?php if (has_local_auth()) { ?>
<div id="AboutMe">
<div class="tables">
<p>Hi <?php echo get_sess_user(); ?>. You can change your password here.</p>
@ -181,9 +243,11 @@ if ($blocklogin === TRUE) {
</tr>
</table>
<input type="hidden" name="formname" value="changepwform">
<input type="hidden" name="id" value="<?php echo get_sess_userid(); ?>">
</form>
</div>
</div>
<?php } ?>
</div>
<script type="text/javascript">
window.csrf_token = '<?php echo CSRF_TOKEN ?>';
@ -441,7 +505,7 @@ $(document).ready(function () {
hoverAnimationDuration: 60,
hoverAnimationEasing: undefined,
items: [
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
<?php if ($allowzoneadd === TRUE) { ?>
{
icon: 'jtable/lib/themes/metro/add.png',
text: 'Import a new zone',
@ -449,6 +513,8 @@ $(document).ready(function () {
$('#ImportZone').jtable('showCreateForm');
}
},
<?php } ?>
<?php if (is_adminuser()) { ?>
{
icon: 'jtable/lib/themes/metro/add.png',
text: 'Clone a zone',
@ -473,6 +539,40 @@ $(document).ready(function () {
addNewRecord: 'Add to ' + zone.name,
noDataAvailable: 'No records for ' + zone.name
},
toolbar: {
items: [
{
text: 'Search zone',
click: function() {
$("#searchzone").dialog({
modal: true,
title: "Search zone for ...",
width: 'auto',
buttons: {
Search: function() {
$( this ).dialog( 'close' );
opentable.find('.jtable-title-text').text(opentableTitle + " (filtered)");
opentable.jtable('load', {
label: $('#searchzone-label').val(),
type: $('#searchzone-type').val(),
content: $('#searchzone-content').val()
});
},
Reset: function() {
$('#searchzone-label').val('');
$('#searchzone-type').val('');
$('#searchzone-content').val('');
$( this ).dialog( 'close' );
opentable.find('.jtable-title-text').text(opentableTitle);
opentable.jtable('load');
return false;
}
}
});
}
}
],
},
paging: true,
sorting: true,
pageSize: 20,
@ -526,12 +626,17 @@ $(document).ready(function () {
'AAAA': 'AAAA',
'CERT': 'CERT',
'CNAME': 'CNAME',
'ALIAS': 'ALIAS',
'LOC': 'LOC',
'NAPTR': 'NAPTR',
'SPF': 'SPF',
'SRV': 'SRV',
'SSHFP': 'SSHFP',
'TLSA': 'TLSA',
'CAA': 'CAA',
'DNAME': 'DNAME',
'DS': 'DS',
'SMIMEA': 'SMIMEA'
};
}
return {
@ -539,6 +644,9 @@ $(document).ready(function () {
'AAAA': 'AAAA',
'CERT': 'CERT',
'CNAME': 'CNAME',
'DNAME': 'DNAME',
'ALIAS': 'ALIAS',
'DS': 'DS',
'LOC': 'LOC',
'MX': 'MX',
'NAPTR': 'NAPTR',
@ -549,7 +657,9 @@ $(document).ready(function () {
'SRV': 'SRV',
'SSHFP': 'SSHFP',
'TLSA': 'TLSA',
'CAA': 'CAA',
'TXT': 'TXT',
'SMIMEA': 'SMIMEA'
};
},
display: displayContent('type'),
@ -609,6 +719,8 @@ $(document).ready(function () {
},
}
}, function (data) {
opentable=data.childTable;
opentableTitle=opentable.find('.jtable-title-text').text();
data.childTable.jtable('load');
});
});
@ -758,7 +870,7 @@ $(document).ready(function () {
type: 'checkbox',
values: {'0': 'No', '1': 'Yes'},
defaultValue: 1,
inputClass: 'overwrite_namerserver'
inputClass: 'overwrite_nameserver'
},
nameserver: {
title: 'Nameservers',
@ -779,7 +891,6 @@ $(document).ready(function () {
}
});
$('#CloneZone').jtable({
title: 'Clone zone',
actions: {
@ -854,18 +965,18 @@ $(document).ready(function () {
});
<?php if (is_adminuser()) { ?>
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#AboutMe').hide();
$('#aboutme').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').show();
});
$('#useradmin').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').hide();
@ -873,7 +984,7 @@ $(document).ready(function () {
$('#Users').show();
});
$('#zoneadmin').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#AboutMe').hide();
$('#MasterZones').show();
@ -884,8 +995,10 @@ $(document).ready(function () {
$('#AboutMe').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#Logs').jtable('load');
$('#Logs').show();
$('#Logs').jtable('load', {
logfile: $('#logfile').val()
});
$('#logs').show();
});
$('#Users').jtable({
title: 'Users',
@ -903,11 +1016,15 @@ $(document).ready(function () {
deleteConfirmation: 'This user will be deleted. Are you sure?'
},
fields: {
id: {
key: true,
type: 'hidden'
},
emailaddress: {
title: 'User',
key: true,
display: displayContent('emailaddress'),
inputClass: 'emailaddress',
edit: false,
listClass: 'emailaddress'
},
password: {
@ -937,8 +1054,7 @@ $(document).ready(function () {
pageSize: 20,
sorting: false,
actions: {
listAction: 'logs.php?action=list',
deleteAction: 'logs.php?action=delete',
listAction: 'logs.php?action=list'
},
messages: {
deleteConfirmation: 'This entry will be deleted. Are you sure?'
@ -948,6 +1064,62 @@ $(document).ready(function () {
hoverAnimationDuration: 60,
hoverAnimationEasing: undefined,
items: [
{
text: 'Search logs',
click: function() {
$("#searchlogs").dialog({
modal: true,
title: "Search logs for ...",
width: 'auto',
buttons: {
Search: function() {
$( this ).dialog( 'close' );
$('#Logs').find('.jtable-title-text').text('Logs (filtered)');
$('#Logs').jtable('load', {
logfile: $('#logfile').val(),
user: $('#searchlogs-user').val(),
entry: $('#searchlogs-entry').val()
});
},
Reset: function() {
$('#searchlogs-user').val('');
$('#searchlogs-entry').val('');
$( this ).dialog( 'close' );
$('#Logs').find('.jtable-title-text').text('Logs');
$('#Logs').jtable('load', {
logfile: $('#logfile').val()
});
return false;
}
}
});
}
},
<?php if($allowrotatelogs === TRUE) { ?>
{
text: 'Rotate logs',
click: function() {
$("#rotatelogs").dialog({
modal: true,
title: "Rotate logs",
width: 'auto',
buttons: {
Ok: function() {
$.get("logs.php?action=rotate");
$( this ).dialog( "close" );
$('#logfile').val('');
$('#Logs').jtable('load');
},
Cancel: function() {
$( this ).dialog( "close" );
return false;
}
}
});
}
},
<?php } ?>
<?php if($allowclearlogs === TRUE) { ?>
{
icon: 'img/delete_inverted.png',
text: 'Clear logs',
@ -960,6 +1132,7 @@ $(document).ready(function () {
Ok: function() {
$.get("logs.php?action=clear");
$( this ).dialog( "close" );
$('#logfile').val('');
$('#Logs').jtable('load');
},
Cancel: function() {
@ -970,17 +1143,18 @@ $(document).ready(function () {
});
}
},
<?php } ?>
{
icon: 'img/export.png',
text: 'Save logs',
text: 'Download logs',
click: function () {
var $zexport = $.get("logs.php?action=export", function(data) {
var $zexport = $.get("logs.php?action=export&logfile=" + $('#logfile').val(), function(data) {
console.log(data);
blob = new Blob([data], { type: 'text/plain' });
var dl = document.createElement('a');
dl.addEventListener('click', function(ev) {
dl.href = URL.createObjectURL(blob);
dl.download = 'nseditlogs.txt';
dl.download = $('#logfile').val() == "" ? 'nseditlogs.txt':$('#logfile').val() + ".txt";
}, false);
if (document.createEvent) {
@ -1016,6 +1190,27 @@ $(document).ready(function () {
}
}
});
$('#logfile').change(function () {
$('#Logs').jtable('load', {
logfile: $('#logfile').val(),
user: $('#searchlogs-user').val(),
entry: $('#searchlogs-entry').val()
});
});
<?php } else { ?>
$('#AboutMe').hide();
$('#aboutme').click(function () {
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').show();
});
$('#zoneadmin').click(function () {
$('#AboutMe').hide();
$('#MasterZones').show();
$('#SlaveZones').show();
});
<?php } ?>
$('#MasterZones').jtable('load');
$('#SlaveZones').jtable('load');

View file

@ -20,32 +20,77 @@ if (!isset($_GET['action'])) {
jtable_respond(null, 'error', 'No action given');
}
switch ($_GET['action']) {
case "list":
global $logging;
if ($logging !== TRUE)
if ($logging !== TRUE) {
jtable_respond(null, 'error', 'Logging is disabled');
} else {
switch ($_GET['action']) {
jtable_respond(getlogs());
case "list":
if(!empty($_POST['logfile'])) {
if(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$_POST['logfile']) == 1) {
$entries=json_decode(file_get_contents($logsdirectory . "/" . $_POST['logfile']),true);
} else {
jtable_respond(null, 'error', "Can't find log file");
break;
}
} else {
$entries=getlogs();
}
if(!empty($_POST['user'])) {
$entries=array_filter($entries,
function ($val) {
return(stripos($val['user'], $_POST['user']) !== FALSE);
}
);
}
if(!empty($_POST['entry'])) {
$entries=array_filter($entries,
function ($val) {
return(stripos($val['log'], $_POST['entry']) !== FALSE);
}
);
}
jtable_respond($entries);
break;
case "delete":
if ($emailaddress != '' and delete_user($emailaddress) !== FALSE) {
jtable_respond(null, 'delete');
case "export":
if(!empty($_GET['logfile'])) {
if(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$_GET['logfile']) == 1) {
$entries=json_decode(file_get_contents($logsdirectory . "/" . $_GET['logfile']),true);
} else {
jtable_respond(null, 'error', 'Could not delete user');
jtable_respond(null, 'error', "Can't find log file");
break;
}
} else {
$entries=getlogs();
}
if(defined('JSON_PRETTY_PRINT')) {
print json_encode($entries,JSON_PRETTY_PRINT);
} else {
print json_encode($entries);
}
break;
case "export":
print json_encode(getlogs());
break;
case "clear":
case "clear":
if($allowclearlogs === TRUE) {
clearlogs();
} else {
jtable_respond(null, 'error', 'Invalid action');
}
break;
default:
case "rotate":
if($allowrotatelogs === TRUE) {
rotatelogs();
} else {
jtable_respond(null, 'error', 'Invalid action');
}
break;
default:
jtable_respond(null, 'error', 'Invalid action');
break;
}
}

16
rotate-logs.php Normal file
View file

@ -0,0 +1,16 @@
<?php
include_once('includes/config.inc.php');
include_once('includes/session.inc.php');
include_once('includes/misc.inc.php');
if(php_sapi_name() !== 'cli') {
echo "This script is intended to be run from the command line";
} else {
if($allowrotatelogs === TRUE) {
$current_user['username']='<system>';
rotatelogs();
} else {
echo "Rotating logs has been disabled."
}
}

View file

@ -0,0 +1,28 @@
{
"name": "Example Template",
"owner": "public",
"records": [
{
"name": "",
"type": "NS",
"content": "ns1.example.com.",
"label": "ns1"
},
{
"name": "",
"type": "NS",
"content": "ns2.example.com.",
"label": "ns2"
},
{
"name": "example-txt",
"type": "TXT",
"content": "This is an example txt record"
},
{
"name": "localhost",
"type": "A",
"content": "127.0.0.1"
}
]
}

View file

@ -64,20 +64,13 @@ case "create":
break;
case "update":
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
$emailaddress = isset($_POST['emailaddress']) ? $_POST['emailaddress'] : '';
$isadmin = isset($_POST['isadmin']) ? $_POST['isadmin'] : '0';
$password = isset($_POST['password']) ? $_POST['password'] : '';
if (!valid_user($emailaddress)) {
jtable_respond(null, 'error', "Please only use ^[a-z0-9@_.-]+$ for usernames");
}
if (!user_exists($emailaddress)) {
jtable_respond(null, 'error', 'Cannot update not existing user');
}
if (update_user($emailaddress, $isadmin, $password)) {
$result = array('emailaddress' => $emailaddress, 'isadmin' => $isadmin);
if ($id != '' and update_user($id, $isadmin, $password)) {
$result = array('isadmin' => $isadmin);
jtable_respond($result, 'single');
} else {
jtable_respond(null, 'error', 'Could not update user');
@ -85,7 +78,9 @@ case "update":
break;
case "delete":
if ($emailaddress != '' and delete_user($emailaddress) !== FALSE) {
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
if ($id != '' and delete_user($id) !== FALSE) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', 'Could not delete user');

View file

@ -12,10 +12,12 @@ if (!is_csrf_safe()) {
jtable_respond(null, 'error', "Authentication required");
}
$quoteus = array('TXT', 'SPF');
/* This function is taken from:
http://pageconfig.com/post/how-to-validate-ascii-text-in-php and got fixed by
#powerdns */
function is_ascii($string) {
return ( bool ) ! preg_match( '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x80-\\xff]/' , $string );
}
@ -112,7 +114,6 @@ function add_db_zone($zonename, $accountname) {
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->bindValue(2, $accountname, SQLITE3_TEXT);
$q->execute();
$db->close();
}
function delete_db_zone($zonename) {
@ -123,7 +124,6 @@ function delete_db_zone($zonename) {
$q = $db->prepare("DELETE FROM zones WHERE zone = ?");
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->execute();
$db->close();
}
function get_zone_account($zonename, $default) {
@ -135,7 +135,6 @@ function get_zone_account($zonename, $default) {
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$result = $q->execute();
$zoneinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
if (isset($zoneinfo['emailaddress']) && $zoneinfo['emailaddress'] != null ) {
return $zoneinfo['emailaddress'];
}
@ -143,6 +142,16 @@ function get_zone_account($zonename, $default) {
return $default;
}
function quote_content($content) {
# empty TXT records are ok, otherwise require surrounding quotes: "..."
if (strlen($content) == 1 || substr($content, 0, 1) !== '"' || substr($content, -1) !== '"') {
# fix quoting: first escape all \, then all ", then surround with quotes.
$content = '"'.str_replace('"', '\\"', str_replace('\\', '\\\\', $content)).'"';
}
return $content;
}
function check_account($zone) {
return is_adminuser() or ($zone->account === get_sess_user());
}
@ -165,7 +174,9 @@ case "listslaves":
foreach ($api->listzones($q) as $sresult) {
$zone = new Zone();
$zone->parse($sresult);
if ($zone->account == '') {
$zone->setAccount(get_zone_account($zone->name, 'admin'));
}
if (!check_account($zone))
continue;
@ -188,6 +199,31 @@ case "listrecords":
$zone = new Zone();
$zone->parse($zonedata);
$records = $zone->rrsets2records();
if(!empty($_POST['label'])) {
$records=array_filter($records,
function ($val) {
return(stripos($val['name'], $_POST['label']) !== FALSE);
}
);
}
if(!empty($_POST['type'])) {
$records=array_filter($records,
function ($val) {
return($val['type'] == $_POST['type']);
}
);
}
if(!empty($_POST['content'])) {
$records=array_filter($records,
function ($val) {
return(stripos($val['content'], $_POST['content']) !== FALSE);
}
);
}
if (isset($_GET['jtSorting'])) {
list($scolumn, $sorder) = preg_split("/ /", $_GET['jtSorting']);
switch ($scolumn) {
@ -248,7 +284,7 @@ case "create":
$zone->importData($_POST['zone']);
}
if (isset($defaults['soa_edit_api'])) {
$zone->setSoaEditApi($defaults['soa_edit_api']);
$zone->setSoaEditApi($defaults['soa_edit_api'], True);
}
if (isset($defaults['soa_edit'])) {
$zone->setSoaEdit($defaults['soa_edit']);
@ -286,7 +322,7 @@ case "create":
if ($template['name'] !== $_POST['template']) continue;
foreach ($template['records'] as $record) {
$rrset = $zone->getRRSet($record['label'], $record['type']);
$rrset = $zone->getRRSet($record['name'], $record['type']);
if ($rrset) {
$rrset->delete();
}
@ -294,7 +330,10 @@ case "create":
$api->savezone($zone->export());
foreach ($template['records'] as $record) {
$zone->addRecord($record['name'], $record['type'], $record['content']);
if ($record['type'] == 'NS') continue;
$name = $record['name'] != '' ? join(Array($record['name'],'.',$zonename)) : $zonename;
$record['content'] = str_replace("[zonename]", $zonename, $record['content']);
$zone->addRecord($name, $record['type'], $record['content']);
}
break;
@ -309,6 +348,8 @@ case "create":
case "update":
$zone = new Zone();
$zone->parse($api->loadzone($_POST['id']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$zoneaccount = isset($_POST['account']) ? $_POST['account'] : $zone->account;
if ($zone->account !== $zoneaccount) {
@ -335,6 +376,8 @@ case "update":
case "createrecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$name = isset($_POST['name']) ? $_POST['name'] : '';
$type = $_POST['type'];
@ -344,12 +387,13 @@ case "createrecord":
$name = $zone->name;
} elseif (string_ends_with($name, '.')) {
# "absolute" name, shouldn't append zone[name] - but check.
$name = substr($name, 0, -1);
if (!string_ends_with($name, $zone->name)) {
jtable_respond(null, 'error', "Name $name not in zone ".$zone->name);
}
} else if (!string_ends_with($name, $zone->name)) {
} else if (!string_ends_with($name.'.', $zone->name)) {
$name = $name . '.' . $zone->name;
} else {
$name = $name.'.';
}
if (!_valid_label($name)) {
@ -362,6 +406,10 @@ case "createrecord":
jtable_respond(null, 'error', "Please only use ASCII-characters in your fields");
}
if (array_search($type, $quoteus) !== FALSE) {
$content = quote_content($content);
}
$record = $zone->addRecord($name, $type, $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
@ -372,16 +420,25 @@ case "createrecord":
case "editrecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
$rrset->deleteRecord($old_record['content']);
$zone->addRecord($_POST['name'], $_POST['type'], $_POST['content'], $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$content = $_POST['content'];
$type = $_POST['type'];
if (array_search($type, $quoteus) !== FALSE) {
$content = quote_content($content);
}
$zone->addRecord($_POST['name'], $_POST['type'], $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
$record = $zone->getRecord($_POST['name'], $_POST['type'], $_POST['content']);
$record = $zone->getRecord($_POST['name'], $_POST['type'], $content);
writelog("Updated record ".$_POST['id']." to ".$record['id']);
jtable_respond($record, 'single');
break;
@ -389,6 +446,8 @@ case "editrecord":
case "deleterecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
@ -419,10 +478,14 @@ case "clone":
$srczone = new Zone();
$srczone->parse($api->loadzone($src));
if ($srczone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$srczone->name);
$srczone->setId('');
$srczone->setName($name);
$srczone->setSerial('');
$srczone->setKind($_POST['kind']);
$zone = $api->savezone($srczone->export());
$srczone->parse($zone);
@ -432,6 +495,15 @@ case "clone":
$newname = preg_replace('/'.$src.'$/', $name, $newname);
$rrset->setName($newname);
}
if (is_adminuser() && isset($_POST['account'])) {
add_db_zone($name, $_POST['account']);
$srczone->setAccount($_POST['account']);
} else {
add_db_zone($name, get_sess_user());
$srczone->setAccount(get_sess_user());
}
$zone = $api->savezone($srczone->export());
writelog("Cloned zone $src into $name");
@ -471,8 +543,11 @@ case "getformnameservers":
break;
case "formzonelist":
$zones = $api->listzones();
usort($zones, "zone_compare");
$ret = array();
foreach ($zones as $zone) {
if (!check_account($zone))
continue;
if ($zone['kind'] == 'Slave')
continue;
array_push($ret, array(