source: trunk/dns-rpc.cgi@ 402

Last change on this file since 402 was 401, checked in by Kris Deugau, 12 years ago

/trunk

Begin updating dns-rpc.cgi. See #43.

Add initRPC() in DNSDB.pm. This sets up the userdata needed
for logging. Prevent the pseudousers added in initRPC() from
being displayed in the user management UI. Sooner or later
this will need to be cleaned up so stale users can be deleted.
Closes #33.

Bring a bit more consistency to error messages, and eliminate
references to odd depths of the code, by adding "\n" to the end
of a few lurking die strings in DNSDB.pm, and all method-sub ones
in dns-rpc.cgi.

Clean up a handful of gross syntax and scope errors from copy-paste
work apparently never checked.

Call new loadConfig() and initRPC() on startup. Add a utility sub
to call from the method subs to check the RPC caller+IP pair against
the new config option.

Update call for delDomain to delZone. Update call to getDomRecs()
to match normalized hash-argument form from r397.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author Id
File size: 12.2 KB
RevLine 
[216]1#!/usr/bin/perl -w -T
[262]2# XMLRPC interface to manipulate most DNS DB entities
3##
[200]4# $Id: dns-rpc.cgi 401 2012-10-03 22:17:51Z kdeugau $
[320]5# Copyright 2012 Kris Deugau <kdeugau@deepnet.cx>
[262]6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19##
[119]20
21use strict;
22use warnings;
[216]23
24# don't remove! required for GNU/FHS-ish install from tarball
25use lib '.'; ##uselib##
26
[119]27use DNSDB; # note we're not importing subs; this lets us (ab)use the same sub names here for convenience
[121]28use Data::Dumper;
[119]29
30#use Frontier::RPC2;
31use Frontier::Responder;
32
33## We need to handle a couple of things globally, rather than pasting the same bit into *every* sub.
34## So, let's subclass Frontier::RPC2 + Frontier::Responder, so we can override the single sub in each
35## that needs kicking
36#### hmm. put this in a separate file?
37#package DNSDB::RPC;
38#our @ISA = ("Frontier::RPC2", "Frontier::Responder");
39#package main;
40
[401]41DNSDB::loadConfig(rpcflag => 1);
[191]42
[119]43# need to create a DNSDB object too
[191]44my ($dbh,$msg) = DNSDB::connectDB($DNSDB::config{dbname}, $DNSDB::config{dbuser},
45 $DNSDB::config{dbpass}, $DNSDB::config{dbhost});
46
[121]47DNSDB::initGlobals($dbh);
[119]48
49my $methods = {
50 'dnsdb.addDomain' => \&addDomain,
[401]51 'dnsdb.delZone' => \&delZone,
[121]52 'dnsdb.addGroup' => \&addGroup,
53 'dnsdb.delGroup' => \&delGroup,
54 'dnsdb.addUser' => \&addUser,
55 'dnsdb.updateUser' => \&updateUser,
56 'dnsdb.delUser' => \&delUser,
57 'dnsdb.getSOA' => \&getSOA,
[123]58 'dnsdb.getRecLine' => \&getRecLine,
59 'dnsdb.getDomRecs' => \&getDomRecs,
60 'dnsdb.getRecCount' => \&getRecCount,
61 'dnsdb.addRec' => \&addRec,
62 'dnsdb.delRec' => \&delRec,
63 'dnsdb.domStatus' => \&domStatus,
[121]64
[119]65 'dnsdb.getMethods' => \&get_method_list
66};
67
68my $res = Frontier::Responder->new(
69 methods => $methods
70 );
71
72# "Can't do that" errors
73if (!$dbh) {
74 print "Content-type: text/xml\n\n".$res->{_decode}->encode_fault(5, $msg);
75 exit;
76}
77##fixme: fail on missing rpcuser/rpcsystem args
78
79print $res->answer;
80
81exit;
82
83##
84## Subs below here
85##
86
[401]87# Utility subs
88sub _aclcheck {
89 my $subsys = shift;
90 return 1 if grep /$ENV{REMOTE_ADDR}/, @{$DNSDB::config{rpcacl}{$subsys}};
91 return 0;
92}
93
[119]94#sub connectDB {
95#sub finish {
96#sub initGlobals {
97#sub initPermissions {
98#sub getPermissions {
99#sub changePermissions {
100#sub comparePermissions {
101#sub changeGroup {
102#sub _log {
103
104sub addDomain {
105 my %args = @_;
106
107 # Make sure we've got all the local bits we need
[401]108 die "Missing remote username\n" if !$args{rpcuser}; # for logging
109 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
110 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]111
112 my ($code, $msg) = DNSDB::addDomain($dbh, $args{domain}, $args{group}, $args{state});
113 die $msg if $code eq 'FAIL';
114 return $msg; # domain ID
115}
116
[401]117sub delZone {
[119]118 my %args = @_;
119
120 # Make sure we've got all the local bits we need
[401]121 die "Missing remote username\n" if !$args{rpcuser}; # for logging
122 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
123 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]124
[401]125# delZone takes zone id and forwrad/reverse flag
[121]126 my ($code,$msg);
[119]127 # Let's be nice; delete based on domid OR domain name. Saves an RPC call round-trip, maybe.
128 if ($args{domain} =~ /^\d+$/) {
[121]129 ($code,$msg) = DNSDB::delDomain($dbh, $args{domain});
[119]130 } else {
131 my $domid = DNSDB::domainID($dbh, $args{domain});
[401]132 die "Can't find domain\n" if !$domid;
[121]133 ($code,$msg) = DNSDB::delDomain($dbh, $domid);
[119]134 }
135 die $msg if $code eq 'FAIL';
136}
137
138#sub domainName {
139#sub domainID {
140
141sub addGroup {
142 my %args = @_;
143
144 # Make sure we've got all the local bits we need
[401]145 die "Missing remote username\n" if !$args{rpcuser}; # for logging
146 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
147 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]148
149# not sure how to usefully represent permissions from any further out from DNSDB.pm :/
[121]150# not to mention, permissions are checked at the UI layer, not the DB layer.
[119]151 my $perms = {domain_edit => 1, domain_create => 1, domain_delete => 1,
152 record_edit => 1, record_create => 1, record_delete => 1
153 };
154## optional $inhert arg?
155 my ($code,$msg) = DNSDB::addGroup($dbh, $args{groupname}, $args{parent_id}, $perms);
156 die $msg if $code eq 'FAIL';
157 return $msg;
158}
159
160sub delGroup {
161 my %args = @_;
162
163 # Make sure we've got all the local bits we need
[401]164 die "Missing remote username\n" if !$args{rpcuser}; # for logging
165 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
166 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]167
[121]168 my ($code,$msg);
[119]169 # Let's be nice; delete based on groupid OR group name. Saves an RPC call round-trip, maybe.
170 if ($args{group} =~ /^\d+$/) {
[121]171 ($code,$msg) = DNSDB::delGroup($dbh, $args{group});
[119]172 } else {
173 my $grpid = DNSDB::groupID($dbh, $args{group});
174 die "Can't find group" if !$grpid;
[121]175 ($code,$msg) = DNSDB::delGroup($dbh, $grpid);
[119]176 }
177 die $msg if $code eq 'FAIL';
178}
179
180#sub getChildren {
181#sub groupName {
182#sub groupID {
183
184sub addUser {
185 my %args = @_;
186
187 # Make sure we've got all the local bits we need
[401]188 die "Missing remote username\n" if !$args{rpcuser}; # for logging
189 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
190 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]191
[121]192# not sure how to usefully represent permissions from any further out from DNSDB.pm :/
193# not to mention, permissions are checked at the UI layer, not the DB layer.
194 my $perms = {domain_edit => 1, domain_create => 1, domain_delete => 1,
195 record_edit => 1, record_create => 1, record_delete => 1
196 };
[119]197 # bend and twist; get those arguments in in the right order!
198 $args{type} = 'u' if !$args{type};
199 $args{permstring} = 'i' if !defined($args{permstring});
200 my @userargs = ($args{username}, $args{group}, $args{pass}, $args{state}, $args{type}, $args{permstring});
201 for my $argname ('fname','lname','phone') {
202 last if !$args{$argname};
203 push @userargs, $args{$argname};
204 }
205 my ($code,$msg) = DNSDB::addUser($dbh, @userargs);
206 die $msg if $code eq 'FAIL';
207 return $msg;
208}
209
210#sub checkUser {
211
212sub updateUser {
213 my %args = @_;
214
215 # Make sure we've got all the local bits we need
[401]216 die "Missing remote username\n" if !$args{rpcuser}; # for logging
217 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
218 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]219
[401]220 die "Missing UID\n" if !$args{uid};
[121]221
222# not sure how to usefully represent permissions from any further out from DNSDB.pm :/
223# not to mention, permissions are checked at the UI layer, not the DB layer.
224 my $perms = {domain_edit => 1, domain_create => 1, domain_delete => 1,
225 record_edit => 1, record_create => 1, record_delete => 1
226 };
[119]227 # bend and twist; get those arguments in in the right order!
228 my @userargs = ($args{uid}, $args{username}, $args{group}, $args{pass}, $args{state}, $args{type});
229 for my $argname ('fname','lname','phone') {
230 last if !$args{$argname};
231 push @userargs, $args{$argname};
232 }
233##fixme: also underlying in DNSDB::updateUser(): no way to just update this or that attribute;
234# have to pass them all in to be overwritten
235 my ($code,$msg) = DNSDB::addUser($dbh, @userargs);
236 die $msg if $code eq 'FAIL';
237}
238
239sub delUser {
240 my %args = @_;
241
242 # Make sure we've got all the local bits we need
[401]243 die "Missing remote username\n" if !$args{rpcuser}; # for logging
244 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
245 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[119]246
[401]247 die "Missing UID\n" if !$args{uid};
[119]248 my ($code,$msg) = DNSDB::delUser($dbh, $args{uid});
249 die $msg if $code eq 'FAIL';
250}
251
252#sub userFullName {
253#sub userStatus {
254#sub getUserData {
255
256sub getSOA {
257 my %args = @_;
258
259 # Make sure we've got all the local bits we need
[401]260 die "Missing remote username\n" if !$args{rpcuser}; # for logging
261 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
262 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[121]263
264 my %ret = DNSDB::getSOA($dbh, $args{def}, $args{id});
265 if (!$ret{recid}) {
266 if ($args{def} eq 'y') {
[401]267 die "No default SOA record in group\n";
[121]268 } else {
[401]269 die "No SOA record in domain\n";
[121]270 }
271 }
272 return \%ret;
[119]273}
274
275sub getRecLine {
276 my %args = @_;
277
278 # Make sure we've got all the local bits we need
[401]279 die "Missing remote username\n" if !$args{rpcuser}; # for logging
280 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
281 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]282
283 my $ret = DNSDB::getRecLine($dbh, $args{def}, $args{id});
284
285 die $DNSDB::errstr if !$ret;
286
287 return $ret;
[119]288}
289
290sub getDomRecs {
291 my %args = @_;
292
293 # Make sure we've got all the local bits we need
[401]294 die "Missing remote username\n" if !$args{rpcuser}; # for logging
295 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
296 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]297
298#bleh
299 $args{nrecs} = 'all' if !$args{nrecs};
300 $args{nstart} = 0 if !$args{nstart};
301## for order, need to map input to column names
302 $args{order} = 'host' if !$args{order};
303 $args{direction} = 'ASC' if !$args{direction};
304
[401]305 my $ret = DNSDB::getDomRecs($dbh, (defrec => $args{defrec}, revrec => $args{revrec}, id => $args{id},
306 offset => $args{offset}, sortby => $args{sortby}, sortorder => $args{sortorder},
307 filter => $args{filter}) );
[123]308
309 die $DNSDB::errstr if !$ret;
310
311 return $ret;
[119]312}
313
[123]314sub getRecCount {
315 my %args = @_;
[119]316
[123]317 # Make sure we've got all the local bits we need
[401]318 die "Missing remote username\n" if !$args{rpcuser}; # for logging
319 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
320 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]321
[401]322 return DNSDB::getRecCount($dbh, $args{id});
[123]323}
324
[119]325sub addRec {
326 my %args = @_;
327
328 # Make sure we've got all the local bits we need
[401]329 die "Missing remote username\n" if !$args{rpcuser}; # for logging
330 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
331 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]332
333 # note dist, weight, port are not reequired on all types; will be ignored if not needed.
[401]334 my ($code, $msg) = DNSDB::addRec($dbh, $args{def}, $args{domid}, $args{host}, $DNSDB::typemap{$args{type}},
[123]335 $args{val}, $args{ttl}, $args{dist}, $args{weight}, $args{port});
336
337 die $msg if $code eq 'FAIL';
[119]338}
339
340sub updateRec {
341 my %args = @_;
342
343 # Make sure we've got all the local bits we need
[401]344 die "Missing remote username\n" if !$args{rpcuser}; # for logging
345 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
346 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]347
348 # note dist, weight, port are not reequired on all types; will be ignored if not needed.
[401]349 my ($code, $msg) = DNSDB::updateRec($dbh, $args{def}, $args{recid}, $args{host}, $DNSDB::typemap{$args{type}},
[123]350 $args{val}, $args{ttl}, $args{dist}, $args{weight}, $args{port});
351
352 die $msg if $code eq 'FAIL';
[119]353}
354
355sub delRec {
356 my %args = @_;
357
358 # Make sure we've got all the local bits we need
[401]359 die "Missing remote username\n" if !$args{rpcuser}; # for logging
360 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
361 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]362
363 # note dist, weight, port are not reequired on all types; will be ignored if not needed.
364 my ($code, $msg) = DNSDB::delRec($dbh, $args{def}, $args{recid});
365
366 die $msg if $code eq 'FAIL';
[119]367}
368
369#sub getParents {
[123]370
371sub domStatus {
372 my %args = @_;
373
374 # Make sure we've got all the local bits we need
[401]375 die "Missing remote username\n" if !$args{rpcuser}; # for logging
376 die "Missing remote system name\n" if !$args{rpcsystem}; # for logging
377 die "Access denied\n" if !_aclcheck($args{rpcsystem});
[123]378
379 my @arglist = ($dbh, $args{domid});
380 push @arglist, $args{status} if defined($args{status});
381
382 my $status = DNSDB::domStatus(@arglist);
383}
384
[119]385#sub importAXFR {
386#sub export {
387#sub __export_tiny {
388
389sub get_method_list {
390 my @methods = keys %{$methods};
391 return \@methods;
392}
Note: See TracBrowser for help on using the repository browser.