1DBI::ProxyServer(3)   User Contributed Perl Documentation  DBI::ProxyServer(3)
2
3
4

NAME

6       DBI::ProxyServer - a server for the DBD::Proxy driver
7

SYNOPSIS

9           use DBI::ProxyServer;
10           DBI::ProxyServer::main(@ARGV);
11

DESCRIPTION

13       DBI::Proxy Server is a module for implementing a proxy for the DBI
14       proxy driver, DBD::Proxy. It allows access to databases over the net‐
15       work if the DBMS does not offer networked operations. But the proxy
16       server might be usefull for you, even if you have a DBMS with inte‐
17       grated network functionality: It can be used as a DBI proxy in a fire‐
18       walled environment.
19
20       DBI::ProxyServer runs as a daemon on the machine with the DBMS or on
21       the firewall. The client connects to the agent using the DBI driver
22       DBD::Proxy, thus in the exactly same way than using DBD::mysql,
23       DBD::mSQL or any other DBI driver.
24
25       The agent is implemented as a RPC::PlServer application. Thus you have
26       access to all the possibilities of this module, in particular encryp‐
27       tion and a similar configuration file. DBI::ProxyServer adds the possi‐
28       bility of query restrictions: You can define a set of queries that a
29       client may execute and restrict access to those. (Requires a DBI driver
30       that supports parameter binding.) See "CONFIGURATION FILE".
31
32       The provided driver script, dbiproxy, may either be used as it is or
33       used as the basis for a local version modified to meet your needs.
34

OPTIONS

36       When calling the DBI::ProxyServer::main() function, you supply an array
37       of options. These options are parsed by the Getopt::Long module.  The
38       ProxyServer inherits all of RPC::PlServer's and hence Net::Daemon's
39       options and option handling, in particular the ability to read options
40       from either the command line or a config file. See RPC::PlServer. See
41       Net::Daemon. Available options include
42
43       chroot (--chroot=dir)
44           (UNIX only)  After doing a bind(), change root directory to the
45           given directory by doing a chroot(). This is usefull for security,
46           but it restricts the environment a lot. For example, you need to
47           load DBI drivers in the config file or you have to create hard
48           links to Unix sockets, if your drivers are using them. For example,
49           with MySQL, a config file might contain the following lines:
50
51               my $rootdir = '/var/dbiproxy';
52               my $unixsockdir = '/tmp';
53               my $unixsockfile = 'mysql.sock';
54               foreach $dir ($rootdir, "$rootdir$unixsockdir") {
55                   mkdir 0755, $dir;
56               }
57               link("$unixsockdir/$unixsockfile",
58                    "$rootdir$unixsockdir/$unixsockfile");
59               require DBD::mysql;
60
61               {
62                   'chroot' => $rootdir,
63                   ...
64               }
65
66           If you don't know chroot(), think of an FTP server where you can
67           see a certain directory tree only after logging in. See also the
68           --group and --user options.
69
70       clients
71           An array ref with a list of clients. Clients are hash refs, the
72           attributes accept (0 for denying access and 1 for permitting) and
73           mask, a Perl regular expression for the clients IP number or its
74           host name.
75
76       configfile (--configfile=file)
77           Config files are assumed to return a single hash ref that overrides
78           the arguments of the new method. However, command line arguments in
79           turn take precedence over the config file. See the "CONFIGURATION
80           FILE" section below for details on the config file.
81
82       debug (--debug)
83           Turn debugging mode on. Mainly this asserts that logging messages
84           of level "debug" are created.
85
86       facility (--facility=mode)
87           (UNIX only) Facility to use for Sys::Syslog. The default is daemon.
88
89       group (--group=gid)
90           After doing a bind(), change the real and effective GID to the
91           given.  This is usefull, if you want your server to bind to a priv‐
92           ileged port (<1024), but don't want the server to execute as root.
93           See also the --user option.
94
95           GID's can be passed as group names or numeric values.
96
97       localaddr (--localaddr=ip)
98           By default a daemon is listening to any IP number that a machine
99           has. This attribute allows to restrict the server to the given IP
100           number.
101
102       localport (--localport=port)
103           This attribute sets the port on which the daemon is listening. It
104           must be given somehow, as there's no default.
105
106       logfile (--logfile=file)
107           Be default logging messages will be written to the syslog (Unix) or
108           to the event log (Windows NT). On other operating systems you need
109           to specify a log file. The special value "STDERR" forces logging to
110           stderr. See Net::Daemon::Log for details.
111
112       mode (--mode=modename)
113           The server can run in three different modes, depending on the envi‐
114           ronment.
115
116           If you are running Perl 5.005 and did compile it for threads, then
117           the server will create a new thread for each connection. The thread
118           will execute the server's Run() method and then terminate. This
119           mode is the default, you can force it with "--mode=threads".
120
121           If threads are not available, but you have a working fork(), then
122           the server will behave similar by creating a new process for each
123           connection.  This mode will be used automatically in the absence of
124           threads or if you use the "--mode=fork" option.
125
126           Finally there's a single-connection mode: If the server has
127           accepted a connection, he will enter the Run() method. No other
128           connections are accepted until the Run() method returns (if the
129           client disconnects).  This operation mode is usefull if you have
130           neither threads nor fork(), for example on the Macintosh. For
131           debugging purposes you can force this mode with "--mode=single".
132
133       pidfile (--pidfile=file)
134           (UNIX only) If this option is present, a PID file will be created
135           at the given location. Default is to not create a pidfile.
136
137       user (--user=uid)
138           After doing a bind(), change the real and effective UID to the
139           given.  This is usefull, if you want your server to bind to a priv‐
140           ileged port (<1024), but don't want the server to execute as root.
141           See also the --group and the --chroot options.
142
143           UID's can be passed as group names or numeric values.
144
145       version (--version)
146           Supresses startup of the server; instead the version string will be
147           printed and the program exits immediately.
148

CONFIGURATION FILE

150       The configuration file is just that of RPC::PlServer or Net::Daemon
151       with some additional attributes in the client list.
152
153       The config file is a Perl script. At the top of the file you may
154       include arbitraty Perl source, for example load drivers at the start
155       (usefull to enhance performance), prepare a chroot environment and so
156       on.
157
158       The important thing is that you finally return a hash ref of option
159       name/value pairs. The possible options are listed above.
160
161       All possibilities of Net::Daemon and RPC::PlServer apply, in particular
162
163       Host and/or User dependent access control
164       Host and/or User dependent encryption
165       Changing UID and/or GID after binding to the port
166       Running in a chroot() environment
167
168       Additionally the server offers you query restrictions. Suggest the fol‐
169       lowing client list:
170
171           'clients' => [
172               { 'mask' => '^admin\.company\.com$',
173                 'accept' => 1,
174                 'users' => [ 'root', 'wwwrun' ],
175               },
176               {
177                 'mask' => '^admin\.company\.com$',
178                 'accept' => 1,
179                 'users' => [ 'root', 'wwwrun' ],
180                 'sql' => {
181                      'select' => 'SELECT * FROM foo',
182                      'insert' => 'INSERT INTO foo VALUES (?, ?, ?)'
183                      }
184               }
185
186       then only the users root and wwwrun may connect from admin.company.com,
187       executing arbitrary queries, but only wwwrun may connect from other
188       hosts and is restricted to
189
190           $sth->prepare("select");
191
192       or
193
194           $sth->prepare("insert");
195
196       which in fact are "SELECT * FROM foo" or "INSERT INTO foo VALUES (?, ?,
197       ?)".
198

Proxyserver Configuration file (bigger example)

200       This section tells you how to restrict a DBI-Proxy: Not every user from
201       every workstation shall be able to execute every query.
202
203       There is a perl program "dbiproxy" which runs on a machine which is
204       able to connect to all the databases we wish to reach. All Perl-DBD-
205       drivers must be installed on this machine. You can also reach databases
206       for which drivers are not available on the machine where you run the
207       programm querying the database, e.g. ask MS-Access-database from Linux.
208
209       Create a configuration file "proxy_oracle.cfg" at the dbproxy-server:
210
211           {
212               # This shall run in a shell or a DOS-window
213               # facility => 'daemon',
214               pidfile => 'your_dbiproxy.pid',
215               logfile => 1,
216               debug => 0,
217               mode => 'single',
218               localport => '12400',
219
220               # Access control, the first match in this list wins!
221               # So the order is important
222               clients => [
223                       # hint to organize:
224                       # the most specialized rules for single machines/users are 1st
225                       # then the denying rules
226                       # the the rules about whole networks
227
228                       # rule: internal_webserver
229                       # desc: to get statistical information
230                       {
231                               # this IP-address only is meant
232                               mask => '^10\.95\.81\.243$',
233                               # accept (not defer) connections like this
234                               accept => 1,
235                               # only users from this list
236                               # are allowed to log on
237                               users => [ 'informationdesk' ],
238                               # only this statistical query is allowed
239                               # to get results for a web-query
240                               sql => {
241                                       alive => 'select count(*) from dual',
242                                       statistic_area => 'select count(*) from e01admin.e01e203 where geb_bezei like ?',
243                               }
244                       },
245
246                       # rule: internal_bad_guy_1
247                       {
248                               mask => '^10\.95\.81\.1$',
249                               accept => 0,
250                       },
251
252                       # rule: employee_workplace
253                       # desc: get detailled informations
254                       {
255                               # any IP-address is meant here
256                               mask => '^10\.95\.81\.(\d+)$',
257                               # accept (not defer) connections like this
258                               accept => 1,
259                               # only users from this list
260                               # are allowed to log on
261                               users => [ 'informationdesk', 'lippmann' ],
262                               # all these queries are allowed:
263                               sql => {
264                                       search_city => 'select ort_nr, plz, ort from e01admin.e01e200 where plz like ?',
265                                       search_area => 'select gebiettyp, geb_bezei from e01admin.e01e203 where geb_bezei like ? or geb_bezei like ?',
266                               }
267                       },
268
269                       # rule: internal_bad_guy_2
270                       # This does NOT work, because rule "employee_workplace" hits
271                       # with its ip-address-mask of the whole network
272                       {
273                               # don't accept connection from this ip-address
274                               mask => '^10\.95\.81\.5$',
275                               accept => 0,
276                       }
277               ]
278           }
279
280       Start the proxyserver like this:
281
282               rem well-set Oracle_home needed for Oracle
283               set ORACLE_HOME=d:\oracle\ora81
284               dbiproxy --configfile proxy_oracle.cfg
285
286       Testing the connection from a remote machine
287
288       Call a programm "dbish" from your commandline. I take the machine from
289       rule "internal_webserver"
290
291               dbish "dbi:Proxy:hostname=oracle.zdf;port=12400;dsn=dbi:Oracle:e01" informationdesk xxx
292
293       There will be a shell-prompt:
294
295               informationdesk@dbi...> alive
296
297               Current statement buffer (enter '/'...):
298               alive
299
300               informationdesk@dbi...> /
301               COUNT(*)
302               '1'
303               [1 rows of 1 fields returned]
304
305       Testing the connection with a perl-script
306
307       Create a perl-script like this:
308
309               # file: oratest.pl
310               # call me like this: perl oratest.pl user password
311
312               use strict;
313               use DBI;
314
315               my $user = shift ⎪⎪ die "Usage: $0 user password";
316               my $pass = shift ⎪⎪ die "Usage: $0 user password";
317               my $config = {
318                       dsn_at_proxy => "dbi:Oracle:e01",
319                       proxy => "hostname=oechsle.zdf;port=12400",
320               };
321               my $dsn = sprintf "dbi:Proxy:%s;dsn=%s",
322                       $config->{proxy},
323                       $config->{dsn_at_proxy};
324
325               my $dbh = DBI->connect( $dsn, $user, $pass )
326                       ⎪⎪ die "connect did not work: $DBI::errstr";
327
328               my $sql = "search_city";
329               printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
330               my $cur = $dbh->prepare($sql);
331               $cur->bind_param(1,'905%');
332               &show_result ($cur);
333
334               my $sql = "search_area";
335               printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
336               my $cur = $dbh->prepare($sql);
337               $cur->bind_param(1,'Pfarr%');
338               $cur->bind_param(2,'Bronnamberg%');
339               &show_result ($cur);
340
341               my $sql = "statistic_area";
342               printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
343               my $cur = $dbh->prepare($sql);
344               $cur->bind_param(1,'Pfarr%');
345               &show_result ($cur);
346
347               $dbh->disconnect;
348               exit;
349
350               sub show_result {
351                       my $cur = shift;
352                       unless ($cur->execute()) {
353                               print "Could not execute\n";
354                               return;
355                       }
356
357                       my $rownum = 0;
358                       while (my @row = $cur->fetchrow_array()) {
359                               printf "Row is: %s\n", join(", ",@row);
360                               if ($rownum++ > 5) {
361                                       print "... and so on\n";
362                                       last;
363                               }
364                       }
365                       $cur->finish;
366               }
367
368       The result
369
370               C:\>perl oratest.pl informationdesk xxx
371               ========================================
372               search_city
373               ========================================
374               Row is: 3322, 9050, Chemnitz
375               Row is: 3678, 9051, Chemnitz
376               Row is: 10447, 9051, Chemnitz
377               Row is: 12128, 9051, Chemnitz
378               Row is: 10954, 90513, Zirndorf
379               Row is: 5808, 90513, Zirndorf
380               Row is: 5715, 90513, Zirndorf
381               ... and so on
382               ========================================
383               search_area
384               ========================================
385               Row is: 101, Bronnamberg
386               Row is: 400, Pfarramt Zirndorf
387               Row is: 400, Pfarramt Rosstal
388               Row is: 400, Pfarramt Oberasbach
389               Row is: 401, Pfarramt Zirndorf
390               Row is: 401, Pfarramt Rosstal
391               ========================================
392               statistic_area
393               ========================================
394               DBD::Proxy::st execute failed: Server returned error: Failed to execute method CallMethod: Unknown SQL query: statistic_area at E:/Perl/site/lib/DBI/ProxyServer.pm line 258.
395               Could not execute
396
397       How the configuration works
398
399       The most important section to control access to your dbi-proxy is
400       "client=>" in the file "proxy_oracle.cfg":
401
402       Controlling which person at which machine is allowed to access
403
404       * "mask" is a perl regular expression against the plain ip-address of
405       the machine which wishes to connect _or_ the reverse-lookup from a
406       nameserver.
407       * "accept" tells the dbiproxy-server wether ip-adresse like in "mask"
408       are allowed to connect or not (0/1)
409       * "users" is a reference to a list of usernames which must be matched,
410       this is NOT a regular expression.
411
412       Controlling which SQL-statements are allowed
413
414       You can put every SQL-statement you like in simply ommiting "sql =>
415       ...", but the more important thing is to restrict the connection so
416       that only allowed queries are possible.
417
418       If you include an sql-section in your config-file like this:
419
420               sql => {
421                       alive => 'select count(*) from dual',
422                       statistic_area => 'select count(*) from e01admin.e01e203 where geb_bezei like ?',
423               }
424
425       The user is allowed to put two queries against the dbi-proxy. The
426       queries are _not_ "select count(*)...", the queries are "alive" and
427       "statistic_area"! These keywords are replaced by the real query. So you
428       can run a query for "alive":
429
430               my $sql = "alive";
431               my $cur = $dbh->prepare($sql);
432               ...
433
434       The flexibility is that you can put parameters in the where-part of the
435       query so the query are not static. Simply replace a value in the where-
436       part of the query through a question mark and bind it as a parameter to
437       the query.
438
439               my $sql = "statistic_area";
440               my $cur = $dbh->prepare($sql);
441               $cur->bind_param(1,'905%');
442               # A second parameter would be called like this:
443               # $cur->bind_param(2,'98%');
444
445       The result is this query:
446
447               select count(*) from e01admin.e01e203
448               where geb_bezei like '905%'
449
450       Don't try to put parameters into the sql-query like this:
451
452               # Does not work like you think.
453               # Only the first word of the query is parsed,
454               # so it's changed to "statistic_area", the rest is omitted.
455               # You _have_ to work with $cur->bind_param.
456               my $sql = "statistic_area 905%";
457               my $cur = $dbh->prepare($sql);
458               ...
459
460       Problems
461
462       * I don't know how to restrict users to special databases.
463       * I don't know how to pass query-parameters via dbish
464

AUTHOR

466           Copyright (c) 1997    Jochen Wiedmann
467                                 Am Eisteich 9
468                                 72555 Metzingen
469                                 Germany
470
471                                 Email: joe@ispsoft.de
472                                 Phone: +49 7123 14881
473
474       The DBI::ProxyServer module is free software; you can redistribute it
475       and/or modify it under the same terms as Perl itself. In particular
476       permission is granted to Tim Bunce for distributing this as a part of
477       the DBI.
478

SEE ALSO

480       dbiproxy, DBD::Proxy, DBI, RPC::PlServer, RPC::PlClient, Net::Daemon,
481       Net::Daemon::Log, Sys::Syslog, Win32::EventLog, syslog
482
483
484
485perl v5.8.8                       2006-02-07               DBI::ProxyServer(3)
Impressum