Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
RPC::PlServer(3)      User Contributed Perl Documentation     RPC::PlServer(3)

       RPC::PlServer - Perl extension for writing PlRPC	servers

	 # Create a subclass of	RPC::PlServer
	 use RPC::PlServer;

	 package MyServer;
	 $MyServer::VERSION = '0.01';
	 @MyServer::ISA	= qw(RPC::PlServer);

	 # Overwrite the Run() method to handle	a single connection
	 sub Run {
	     my	$self =	shift;
	     my	$socket	= $self->{'socket'};

	 # Create an instance of the MyServer class
	 package main;
	 my $server = MyServer->new({'localport' => '1234'}, \@ARGV);

	 # Bind	the server to its port to make it actually running

       PlRPC (Perl RPC)	is a package for implementing servers and clients that
       are written in Perl entirely. The name is borrowed from Sun's RPC
       (Remote Procedure Call),	but it could as	well be	RMI like Java's
       "Remote Method Interface), because PlRPC	gives you the complete power
       of Perl's OO framework in a very	simple manner.

       RPC::PlServer is	the package used on the	server side, and you guess
       what RPC::PlClient is for. Both share the package RPC::PlServer::Comm
       for communication purposes. See PlRPC::Client(3)	and
       RPC::PlServer::Comm for these parts.

       PlRPC works by defining a set of	methods	that may be executed by	the
       client.	For example, the server	might offer a method "multiply"	to the
       client. Now the clients method call

	   @result = $client->multiply($a, $b);

       will be immediately mapped to a method call

	   @result = $server->multiply($a, $b);

       on the server. The arguments and	results	will be	transferred to or from
       the server automagically. (This magic has a name	in Perl: It's the
       Storable	module,	my thanks to Raphael Manfredi for this excellent
       package.) Simple, eh? :-)

       The RPC::PlServer and RPC::PlClient are abstract	servers	and clients:
       You have	to derive your own classes from	it.

   Additional options
       The RPC::PlServer inherits all of Net::Daemon's options and attributes
       and adds	the following:

       cipher  The attribute value is an instance of Crypt::DES, Crypt::IDEA
	       or any other class with the same	API for	block encryption. If
	       you supply such an attribute, the traffic between client	and
	       server will be encrypted	using this option.

       maxmessage (--maxmessage=size)
	       The size	of messages exchanged between client and server	is
	       restricted, in order to omit denial of service attacks. By
	       default the limit is 65536 bytes.

       users   This is an attribute of the client object used for Permit/Deny
	       rules in	the config file. It's value is an array	ref of user
	       names that are allowed to connect from the given	client.	See
	       the example config file below. "CONFIGURATION FILE".

   Error Handling
       Error handling is simple	with the RPC package, because it is based on
       Perl exceptions completely. Thus	your typical code looks	like this:

	 eval {
	     # Do something here. Don't	care for errors.
	 if ($@) {
	     # An error	occurred.

   Server Constructors
	 my $server = RPC::PlServer(\%options, \@args);

       (Class method) This constructor is immediately inherited	from the
       Net::Daemon package. See	Net::Daemon(3) for details.

   Access Control
	 $ok = $self->AcceptApplication($app);
	 $ok = $self->AcceptVersion($version);
	 $ok = $self->AcceptUser($user,	$password);

       The RPC::PlServer package has a very detailed access control scheme:
       First of	all it inherits	Net::Daemon's host based access	control. It
       adds version control and	user authorization. To achieve that, the
       method Accept from Net::Daemon is split into three methods,
       AcceptApplication, AcceptVersion	and AcceptUser,	each of	them returning
       TRUE or FALSE. The client receives the arguments	as the attributes
       application, version, user and password.	A client is accepted only if
       all of the above	methods	are returning TRUE.

       The default implementations are as follows: The AcceptApplication
       method returns TRUE, if $self is	a subclass of $app. The	AcceptVersion
       method returns TRUE, if the requested version is	less or	equal to
       ${$class}::VERSION, $self being an instance of $class. Whether a	user
       is permitted to connect depends on the client configuration. See
       "CONFIGURATION FILE" below for examples.

   Method based	access control
       Giving a	client the ability to invoke arbitrary methods can be a
       terrible	security hole. Thus the	server has a methods attribute.	This
       is a hash ref of	class names as keys, the values	being hash refs	again
       with method names as the	keys. That is, if your hash looks as follows:

	   $self->{'methods'} =	{
	       'CalcServer' => {
		   'NewHandle' => 1,
		   'CallMethod'	=> 1 },
	       'Calculator' => {
		   'new' => 1,
		   'multiply' => 1,
		   'add' => 1,
		   'divide' => 1,
		   'subtract' => 1 }

       then the	client may use the CalcServer's	NewHandle method to create
       objects,	but only via the permitted constructor Calculator->new.	Once a
       Calculator object is created, the server	may invoke the methods
       multiply, add, divide and subtract.

       The server config file is inherited from	Net::Daemon. It	adds the users
       and cipher attribute to the client list.	Thus a typical config file
       might look as follows:

	   # Load external modules; this is not	required unless	you use
	   # the chroot() option.
	   #require DBD::mysql;
	   #require DBD::CSV;

	   # Create keys
	   my $myhost_key = Crypt::IDEA->new('83fbd23390ade239');
	   my $bob_key	  = Crypt::IDEA->new('be39893df23f98a2');

	       # 'chroot' => '/var/dbiproxy',
	       'facility' => 'daemon',
	       'pidfile' => '/var/dbiproxy/',
	       'user' => 'nobody',
	       'group' => 'nobody',
	       'localport' => '1003',
	       'mode' => 'fork',

	       # Access	control
	       'clients' => [
		   # Accept the	local LAN (192.168.1.*)
		       'mask' => '^192\.168\.1\.\d+$',
		       'accept'	=> 1,
		       'users' => [ 'bob', 'jim' ],
		       'cipher'	=> $myhost_key
		   # Accept
		       'mask' => '^myhost\.company\.com$',
		       'accept'	=> 1,
		       'users' => [ {
			   'name' => 'bob',
			   'cipher' => $bob_key
			   } ]
		   # Deny everything else
		       'mask' => '.*',
		       'accept'	=> 0

       Things you should note: The user	list of	192.168.1.* contains scalar
       values, but the user list of contains	hash refs:
       This is required, because the user configuration	is more	specific for
       user based encryption.

       Enough wasted time, spread the example, not the word. :-) Let's write a
       simple server, say a server for MD5 digests. The	server uses the
       external	package	MD5, but the client doesn't need to install the
       package.	MD5(3).	We present the server source here, the client is part
       of the RPC::PlClient man	page. See RPC::PlClient(3).

	   #!/usr/bin/perl -wT
	   # Note the -T switch! This is always	recommended for	Perl servers.

	   use strict;		     # Always a	good choice.

	   require RPC::PlServer;
	   require MD5;

	   package MD5_Server;	# Clients need to request application
				# "MD5_Server"

	   $MD5_Server::VERSION	= '1.0'; # Clients will	be refused, if they
					 # request version 1.1
	   @MD5_Server::ISA = qw(RPC::PlServer);

	   eval	{
	       # Server	options	below can be overwritten in the	config file or
	       # on the	command	line.
	       my $server = MD5_Server->new({
		   'pidfile'	=> '/var/run/',
		   'configfile'	=> '/etc/md5serv.conf',
		   'facility'	=> 'daemon', # Default
		   'user'	=> 'nobody',
		   'group'	=> 'nobody',
		   'localport'	=> 2000,
		   'logfile'	=> 0,	     # Use syslog
		   'mode'	=> 'fork',   # Recommended for Unix
		   'methods'	=> {
		       'MD5_Server' => {
			   'ClientObject' => 1,
			   'CallMethod'	=> 1,
			   'NewHandle' => 1
		       'MD5' =>	{
			   'new' => 1,
			   'add' => 1,
			   'hexdigest' => 1

       It has to be said: PlRPC	based servers are a potential security
       problem!	 I did my best to avoid	security problems, but it is more than
       likely, that I missed something.	Security was a design goal, but	not
       *the* design goal. (A well known	problem	...)

       I highly	recommend the following	design principles:

   Protection against "trusted"	users
	   Read	the perl security FAQ ("perldoc	perlsec") and use the "-T"

	   Use the "-T"	switch.	I mean it!

       Verify data
	   Never untaint strings withouth verification,	better verify twice.
	   For example the CallMethod function first checks, whether an	object
	   handle is valid before coercing a method on it.

       Be restrictive
	   Think twice,	before you give	a client access	to a method.

	   And just in case I forgot it: Read the "perlsec" man	page. :-)

   Protection against untrusted	users
       Host based authorization
	   PlRPC has a builtin host based authorization	scheme;	use it!	 See

       User based authorization
	   PlRPC has a builtin user based authorization	scheme;	use it!	 See

	   Using encryption with PlRPC is extremely easy. There	is absolutely
	   no reason for communicating unencrypted with	the clients. Even
	   more: I recommend two phase encryption: The first phase is the
	   login phase,	where to use a host based key. As soon as the user has
	   authorized, you should switch to a user based key. See the
	   DBI::ProxyServer for	an example.

       The PlRPC-modules are

	 Copyright (C) 1998, Jochen Wiedmann
			     Email: jochen.wiedmann at

	 All rights reserved.

       You may distribute this package under the terms of either the GNU
       General Public License or the Artistic License, as specified in the
       Perl README file.

       RPC::PlClient(3), RPC::PlServer::Comm(3), Net::Daemon(3),
       Net::Daemon::Log(3), Storable(3), Sys::Syslog(3), Win32::EventLog(3)

       See DBI::ProxyServer(3) for an example application.

perl v5.32.1			  2007-06-17		      RPC::PlServer(3)


Want to link to this manual page? Use this URL:

home | help