source: trunk/cgi-bin/search-rpc.cgi@ 903

Last change on this file since 903 was 903, checked in by Kris Deugau, 7 years ago

/trunk

Add RPC script for IPDB search. Contains the skeleton of the underlying
widgetry needed for the full search refresh. See #4.

  • Property svn:executable set to *
File size: 4.6 KB
Line 
1#!/usr/bin/perl
2# XMLRPC interface to IPDB search
3# Copyright (C) 2017 Kris Deugau <kdeugau@deepnet.cx>
4
5use strict;
6use warnings;
7
8use DBI;
9use CustIDCK;
10use NetAddr::IP;
11use FCGI;
12use Frontier::Responder;
13
14use Sys::Syslog;
15
16# don't remove! required for GNU/FHS-ish install from tarball
17##uselib##
18
19use MyIPDB;
20
21openlog "IPDB-search-rpc","pid","$IPDB::syslog_facility";
22
23##fixme: username source? can we leverage some other auth method?
24# we don't care except for logging here, and Frontier::Client needs
25# a patch that's not well-distributed to use HTTP AUTH.
26
27# Collect the username from HTTP auth. If undefined, we're in
28# a test environment, or called without a username.
29my $authuser;
30if (!defined($ENV{'REMOTE_USER'})) {
31 $authuser = '__temptest';
32} else {
33 $authuser = $ENV{'REMOTE_USER'};
34}
35
36# Why not a global DB handle? (And a global statement handle, as well...)
37# Use the connectDB function, otherwise we end up confusing ourselves
38my $ip_dbh;
39my $sth;
40my $errstr;
41($ip_dbh,$errstr) = connectDB_My;
42initIPDBGlobals($ip_dbh);
43
44my $methods = {
45 'ipdb.search' => \&rpc_search,
46};
47
48my $reqcnt = 0;
49
50my $req = FCGI::Request();
51
52# main FCGI loop.
53while ($req->Accept() >= 0) {
54 # done here to a) prevent $ENV{'REMOTE_ADDR'} from being empty and b) to collect
55 # the right user for the individual call (since we may be running with FCGI)
56 syslog "debug", "$authuser active, $ENV{'REMOTE_ADDR'}";
57
58 # don't *think* we need any of these...
59 # %disp_alloctypes, %def_custids, %list_alloctypes
60 # @citylist, @poplist
61 # @masterblocks, %allocated, %free, %bigfree, %routed (removed in /trunk)
62 # %IPDBacl
63 #initIPDBGlobals($ip_dbh);
64
65 my $res = Frontier::Responder->new(
66 methods => $methods
67 );
68
69 # "Can't do that" errors
70 if (!$ip_dbh) {
71 print "Content-type: text/xml\n\n".$res->{_decode}->encode_fault(5, $DBI::errstr);
72 } else {
73 print $res->answer;
74 }
75 last if $reqcnt++ > $IPDB::maxfcgi;
76} # while FCGI::accept
77
78exit 0;
79
80
81##
82## Private subs
83##
84
85# Check RPC ACL
86sub _aclcheck {
87 my $subsys = shift;
88 return 1 if grep /$ENV{REMOTE_ADDR}/, @{$IPDB::rpcacl{$subsys}};
89 warn "$subsys/$ENV{REMOTE_ADDR} not in ACL\n"; # a bit of logging
90 return 0;
91}
92
93sub _commoncheck {
94 my $argref = shift;
95 my $needslog = shift;
96
97 die "Missing remote system name\n" if !$argref->{rpcsystem};
98 die "Access denied\n" if !_aclcheck($argref->{rpcsystem});
99 if ($needslog) {
100 die "Missing remote username\n" if !$argref->{rpcuser};
101 }
102}
103
104# stripped-down copy from from main.cgi. should probably be moved to IPDB.pm
105sub _validateInput {
106 my $argref = shift;
107
108 if (!$argref->{block}) {
109 $argref->{block} = $argref->{cidr} if $argref->{cidr};
110 die "Block/IP is required\n" if !$argref->{block};
111 }
112
113 # Alloctype check.
114 chomp $argref->{type};
115
116 die "Invalid allocation type\n" if (!grep /$argref->{type}/, keys %disp_alloctypes);
117
118 # Arguably not quite correct, as the custID won't be checked for
119 # validity if there's a default on the type.
120 if ($def_custids{$argref->{type}} eq '') {
121 # Types without a default custID must have one passed in
122 die "Customer ID is required\n" if !$argref->{custid};
123 # Crosscheck with billing.
124 my $status = CustIDCK->custid_exist($argref->{custid});
125 die "Error verifying customer ID: $CustIDCK::ErrMsg\n" if $CustIDCK::Error;
126 die "Customer ID not valid\n" if !$status;
127 } else {
128 # Types that have a default will use it unless one is specified.
129 if ((!$argref->{custid}) || ($argref->{custid} ne 'STAFF')) {
130 $argref->{custid} = $def_custids{$argref->{type}};
131 }
132 }
133} # end validateInput()
134
135
136##
137## RPC method subs
138##
139
140sub rpc_search {
141 my %args = @_;
142
143 _commoncheck(\%args, 'n');
144
145 my $sql = q(SELECT s.cidr,s.custid,s.type,s.description,a.dispname FROM searchme s JOIN alloctypes a ON s.type = a.type);
146
147 my @fields;
148 my @vals;
149 my @matchtypes;
150
151 my %mt = (EXACT => '=',
152 NOT => '!~',
153 );
154
155 if ($args{type}) {
156 push @fields, 's.type';
157 push @vals, $args{type};
158 push @matchtypes, '=';
159 }
160 if ($args{cidr}) {
161 # Magic!
162 }
163 foreach (qw(custid description notes city) ) {
164 if ($args{$_}) {
165 push @fields, "s.$_";
166 if ($args{$_} =~ /^(EXACT|NOT):/) {
167 push @matchtypes, $mt{$1};
168 $args{$_} =~ s/^(?:EXACT|NOT)://;
169 } else {
170 push @matchtypes, '~*';
171 }
172 push @vals, $args{$_};
173 }
174 }
175
176 my @sqlcriteria;
177 for (my $i = 0; $i <= $#fields; $i++) {
178 push @sqlcriteria, "$fields[$i] $matchtypes[$i] ?";
179 }
180 $sql .= " WHERE ".join(' AND ', @sqlcriteria) if @sqlcriteria;
181
182 my $result = $ip_dbh->selectall_arrayref($sql, {Slice=>{}}, @vals);
183 die $ip_dbh->errstr if !$result;
184
185 return $result;
186} # rpc_search()
187
Note: See TracBrowser for help on using the repository browser.