ARCv2

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

Revision history for Perl extension ARCv2.

1.05- Tue Mar 22 2005
	- fixed authentication/decryption problem, which lead to
	  staling connections when the client thought it is authenticated,
	  but the server doesn't know that
	- correct the exit-code handling in the arcx-client-script
	- another patch by Tony Fraser (ACLs, CheckCmd for the Server-Connection)
	- command-server-mapping-file for arcx-client-script

1.04  Tue Jan 04 2005
	- Fixed timeout again
	- command error handling improved, passed to the client separatly now

1.03  Tue Dec 02 2004
	- Documentation has to be created
	- line feed when command sprays an error (thanks to Wolfgang Friebel)
	- pid file
	- removed errornous white space

1.02  Tue Nov 02 2004
	- corrected a typo (forgot a $) (thanks to Tony Fraser)
	- added a member-variable to allow changable server connection type
	  this makes extending Arc::Connection::Server more easier to use it then
	  with Arc::Server (suggested by Tony Fraser, thanks)
	- timeout behaviour for command connection fixed (thanks to Wolfgang Friebel)
	- workaround bug regarding asynchonous sasl-encryption within one connection

1.01  Wed Jul 28 2004
	- commandconnection is now using IO::Select for accepting
	- added init.d script for solaris

1.00  Wed Jul 28 2004
    - change the loglevel behaviour
	- ported the server to Net::Server::PreFork
	- encrypted protocol connection (new protocol version)
    - added PBConfig for easier Makefile.PL
    - Missing dependencies fix
	- fix documentation for arcx (thanks to Andreas Haupt)

Changes  view on Meta::CPAN

0.06  Mon Mar 08 2004
    - Solaris make fix

0.05  Wed Mar 03 2004
    - changed instance to object in documentation
	- heavy documentation update (thanks to Wolfgang Friebel for reading
	  all this pages)
	- deadlock fixed in when the client uses the same object to reconnect
	  (arcx)
	- arcx reconnects automatically when lost connection during a session
	- small bug in Put command
	- put all .pm file in lib/

0.04  Tue Jan 27 2004
	- Added the raw pod documentation to the package. The installation
	  process will now build the pod when running perl Makefile.PL.
	- Updating Documentation (for arcx and arcxd).
	- Removed some debug statements. (also known as 'code cleanup').
	- Added the IP*PORT parameter to SASL *_new function, KERBEROS_V4
	  is possible now (depends on Authen::SASL::Cyrus 0.10)
	- removed the CheckAcl method from the Command class, since there
	  is apparently no need for it.

0.03  Fri Jan 23 2004
	- Documentation improvements (reimplemented members are hidden)
	- Name for ARCv2 command line interface (arcx, arcxd) 01/23/2004
		- Arc Extended
	- Makefile.PL improvements
	- default values for host, path and port during Makefile.PL
	- first DESY Zeuthen production release.

0.02  Thu Jan 22 2004
	- removed Config::IniFiles from Arc classes
	- improved signal handling
	- added client and server scripts, to be
	  able to use the client and start the server
	  from command line
	- documentation
	- structured internal variable access

0.01  Tue Dec  9 16:46:42 2003
	- original version; created by h2xs 1.22 with options

lib/Arc.pm  view on Meta::CPAN

sub _Debug
{
	my $this = shift;
	$this->Log(LOG_DEBUG,@_);
}

## Log function.
## Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
## loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
## LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
## LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
## information), LOG_DEBUG (verbose debug information). It possible to combine the 
## levels with or (resp. +) to allow a message to appear when not all loglevels are 
## requested by the user.
## Commonly used for logging errors from application level.
##in> $facility, ... (message)
##out> always false
##eg> return $arc->Log(LOG_ERR,"Message");
sub Log
{
	my $this = shift;

lib/Arc.pod  view on Meta::CPAN

=head1 NAME

Arc - Authenticated Remote Control v2

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

This is a abstract (known from c++) class. 
This is the base class which defines the namespace for 
the ARCv2 module suite.


=head1 Class VARIABLES

lib/Arc.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) 

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/Arc/Command.pm  view on Meta::CPAN

@Arc::Command::ISA = qw(Arc);

# Friend class Arc::Connection::Server;
sub members 
{
	my $this = shift;
	return { %{$this->SUPER::members},
		# private:
			
		# protected:
			_commands => {},    # the "available commands"-hash from the server, 
			_username => "",    # user, who has authenticated against ARCv2 Server by using SASL
			_realm => "",       # the name of the realm, to which the user belongs (SASL)
			_mech => undef,     # user uses this authentication mechanism (e.g. GSSAPI)
			_peeraddr => undef, # users ip address
			_peername => undef, # users host address in sockaddr_in format
			_peerport => undef, # users port
			_cmd => undef,      # user runs this command

		# public: 
			logfileprefix => "command",
	};
}

## execute this command.
## This function is called by the ARCv2 Server when the user wants 
## to execute this command. 
##in> ... (parameter from users request)
##out> true if the command has succeeded, false (and please set _SetError) if not.
sub Execute
{
	my $this = shift;
	
	return 1;
}

return 1;

lib/Arc/Command.pod  view on Meta::CPAN

=head1 NAME

Arc::Command - Abstract base class for ARCv2 commands

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

This module is part of the module suite ARCv2.

This is the command module from ARCv2. If we would use C++, we would say
this is an abstract class of an ARC Command. All commands used by ARCv2 should
derive from this class.

=head1 HOW DOES IT WORKS

This abstract class is the base class for all existing ARCv2 commands and 
should be the base class for all new ARCv2 commands.
 
When starting the ARCv2 Server you have to pass a important hash:

 $arc = new Arc::Server ( 
    [..] Arc::Server vars [..],
   connection_vars => { 
      commands => { 
        'pv' => 'Arc::Command::Pv'
      } 
   }
 )  
 
 resp.

 $arc->{connection_vars}->{commands}

This hash describes the assignment of B<Command Name> and B<Command Class>. 
When a client has authenticated and wants to run a command, it will send 
the B<Command Name> and suitable, optional parameters. The server will look into 
the commands hash and creates an object of the B<Command Class> 
associated with B<Command Name>.

 my $perlcmd = $this->{commands}->{$cmd};
 [..]
 eval "require $perlcmd;"
 [..]
 (fork)
 my $ret = eval
 {
  my $object = new $perlcmd(
    _username => $this->{_username},
    _peeraddr => $this->{peeraddr},
    _peerport => $this->{peerport},
    _peername => $this->{peername},
    _cmd => $cmd,
    logfileprefix => "command",
  );
  $object->Execute(@a);
  $cmderr = $object->IsError();

  return -1;
 };
 
When everything went alright, the command will be executed. The command runs
in a separate process. Therefore STDIN, STDOUT and STDERR are duped to two
pipes, one for the in, one for the out direction. In the parent process data
from the encrypted network command connection is read from and written to these pipes.
Same situation on the client side, STDIN and STDOUT are used to put and get the 
data through the network.
 
                   encrypted
          /--->>---| net- |--->>-----\   
        / /---<<---| work |---<<-----\ \
      / /                              \ \
     | |     in                         | |    p2
  |--------|->>--\                  |--------|->>--\ 
  | Client | out   \                | Server | p1    \

lib/Arc/Command.pod  view on Meta::CPAN

 sub Execute 
 {
  while ($_ = <STDIN>) { # ends on EOF
     s/a/b/g; print;
  }
 }
 
If you want to implement a new Command for ARCv2 you have to derive from 
Arc::Command and override the sub C<Execute>. See existing Arc::Command::* 
classes for examples. To get your Command recognised you have to assign a 
B<Command Name> to your command class. ARCv2 ignores the return code of
B<Execute>. If your command runs into an error use the _SetError function 
and return immediately. This is what ARCv2 will evaluate and send to the
client.

B<Example>:
 sub Execute
 {
  my $this = shift;
  my $pw = <>;
  if ($pw ne "klaus") {
	  return $this->_SetError("Wrong password.");
  }
 }
 
In ARCv2 some standard commands are already implemented: C<Arc::Command::Get>,
C<Arc::Command::Put>, C<Arc::Command::Uptime>, C<Arc::Command::Whoami>,
C<Arc::Command::Test>.

By default, these classes are mapped to B<Command Names> as follows (in the 
default arcxd.conf for arcxd):
  uptime => Arc::Command::Uptime,
  whoami => Arc::Command::Whoami,
  copy   => Arc::Command::Get,
  cp     => Arc::Command::Get,
  get    => Arc::Command::Get,
  put    => Arc::Command::Put,
  test   => Arc::Command::Test,
  help   => Arc::Command::Help,
 
B<Caution>: Especially take care of the C<Arc::Command::Get> and 
C<Arc::Command::Put> in production environment. As ARCv2 will probably
run as root and by default the Get and Put command do NOT have an access
control, everyone can get or put any files from/to your ARCv2 server.

There are some member variables, which contain information about the 
client. See 'Class VARIABLES' for a complete list of them. These values 
are filled by Arc::Connection::Server, when the client wants to run a command.


=head1 Class VARIABLES

=head3 PUBLIC MEMBERS

=over 2

=item logfileprefix I<reimplemented from Arc>

B<Default value>: "command"

=back 

=over 2

=item logdestination I<inherited from Arc>

B<Description>: Where should all the log output go to ('stderr','syslog')

B<Default value>: 'syslog'

lib/Arc/Command.pod  view on Meta::CPAN

=over 2

=back 

=head3 PROTECTED MEMBERS

=over 2

=item _cmd 

B<Description>: user runs this command

B<Default value>: undef

=item _commands 

B<Description>: the "available commands"-hash from the server, 

B<Default value>: {}

=item _mech 

B<Description>: user uses this authentication mechanism (e.g. GSSAPI)

B<Default value>: undef

=item _peeraddr 

lib/Arc/Command.pod  view on Meta::CPAN

=head3 PRIVATE MEMBERS

=head1 Class METHODS

=head3 PUBLIC METHODS

=over 2

=item Execute ( ... (parameter from users request) ) 

B<Description>: execute this command.
This function is called by the ARCv2 Server when the user wants 
to execute this command. 


B<Returns:> true if the command has succeeded, false (and please set _SetError) if not.


=back 

=over 2

=item DESTROY (  ) I<inherited from Arc>

B<Description>: Destructor

lib/Arc/Command.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) I<inherited from Arc>

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/Arc/Command/Help.pm  view on Meta::CPAN

sub Execute
{
	my $this = shift;

	print "This is $Arc::Copyright\n";
	print "Please report bugs to: $Arc::Contact\n";
	
	print "\n";
	print "Available Commands:\n";

# sort command 
	my %h;

	foreach (keys %{$this->{_commands}}) {
		push (@{$h{$this->{_commands}->{$_}}}, $_);
	}
	
	foreach (sort keys %h) {
		print "\t",join (", ",@{$h{$_}}),"\n";
	}
	
	
	1;
}

lib/Arc/Connection.pm  view on Meta::CPAN

sub members 
{
	my $this = shift;
	return { %{$this->SUPER::members},
		# private:
			__sasl => undef,   # Authen::SASL Handle
			__linequeue => [], # internal line buffer (idea From Net::Cmd)
			__partial => "",   # a partial line (idea From Net::Cmd)
		# protected:
			_connection => undef,    # IO::Socket for the ARCv2 Connection
			_cmdclientsock => undef, # IO::Socket for the command connection (encrypted)
			_select => undef,        # IO::Select for the ARCv2 Connection
			
			_authenticated => 0,     # Are we authenticated
			#_sasl => undef,         # Authen::SASL::Cyrus Handle
			#_saslmech => "",        # SASL mechnanism used at authentication
			
			_cmdparameter => undef,   # parameter after the command
			_expectedcmds => undef,   # array, which ARCv2 protocol commands are allowed to come next
			_connected => 0,          # are we connected
			_username => "anonymous", # username extracted from SASL

		# public:
			protocol => undef, # Which protocol is used (0 = ARC/2.0, 1 = ARC/2.1)

			timeout => undef,  # timeout for all connections (ARCv2 and command) in seconds
			service => undef,  # name of the server (for SASL)
	};
}

sub _Init
{
	my $this = shift;
		 
	return $this->_SetError("Initialization failed.") unless $this->SUPER::_Init(@_);
	

lib/Arc/Connection.pm  view on Meta::CPAN

#		$this->Log(LOG_SIDE,"Setting timeout to 30 secs since no time specified.");
#		$this->{timeout} = 30;
#	}		  
	
	return $this->_SetError("No service name for SASL authentication specified.") 
		unless defined $this->{service};
		
	return 1; 
}

## initializes command connection. (protocol)
## Starts listen on the Command socket and sends the B<CMDPASV> command.
##out> true if everything went like expected, otherwise false.
##eg> $this->_CommandConnection();
sub _CommandConnection
{
	my $this = shift;

	my $consock = IO::Socket::INET->new(
				Listen    => 1,
				Proto     => 'tcp',
				LocalAddr => $this->{_connection}->sockhost,

lib/Arc/Connection.pm  view on Meta::CPAN

			if ($sock == $consock) {
				$this->{_cmdclientsock} = $consock->accept() || last;
				return 1;
			}
		}
	} else {
		return $this->_SetError("No CommandConnection received (Client died?).");
	}	
}

## function for reading and writing on the command connection.
## This function is always used by the C<Arc::Connection::Server> to handle 
## command data. When calling the C<ProcessCommand> from C<Arc::Connection::Client> 
## this function is also used.
## Data is read from the local socket resp. pipe and is written encrypted 
## to the network socket. The other side reads the data from network socket, 
## decrypts it and writes it to its local socket. This function behaves differently on 
## client and server sides, when the local or network socket is closed.
##in> *locfdin, *locfdout
##out> always true
##eg> $this->ReadWriteBinary(*STDIN,*STDOUT);
sub _ReadWriteBinary
{

lib/Arc/Connection.pm  view on Meta::CPAN

			# We don't want to listen to it anymore
			unless ($ret) {
				$sel->remove($r);
				# If there is nothing to read anymore
				# we will never write to the other socket again.
				if ($r->fileno == $locin->fileno) {
					$stop = 1 unless $client;
					shutdown($netsock,1); # Close write connection
				} elsif ($r->fileno == $netsock->fileno) {
					# on client-side the netsock is closed only
					# if the command on server side has ended.
					# so game over
					$stop = 1 if $client;
					close($locout) unless $stop; # Local pipe is not needed anymore
				}
				
				last if $stop;
			} else {
				# select the appropriate write-"select"
				my $tsel = $r->fileno == $locin->fileno ? $nwsel : $lwsel;
				# encryption, decode or encode

lib/Arc/Connection.pm  view on Meta::CPAN

			}
		}
		last if $stop;
	}

#	$this->_Debug("RW Binary ended.");
	return 1;
}

## send a line. (protocol)
## This function sends a command line to the ARCv2 socket.
##in> ... (line)
##out> true if writing has succeeded, otherwise false.
##eg> $this->_SendLine($cmd,"test"); 
sub _SendLine
{
	my $this = shift;
	return unless @_;
	my $line = join("",@_);
	$line =~ s/\r//g;
	$line =~ s/\n/ /g;

lib/Arc/Connection.pm  view on Meta::CPAN

			if $this->{_authenticated} == 1 and $this->{protocol} == 1;

		return $this->{_connection}->syswrite($line,4096) > 0;
	} else {
		$this->{_connected} = 0;
		$this->{_connection}->close;
		return $this->_SetError("Sending timed out.");
	}
}

## send a command. (protocol)  
## Send a command to the ARCv2 socket.
##in> $cmd, $parameter
##out> true if successful, otherwise false
##eg> $this->_SendCommand("CMDPASV",$consock->sockhost.':'.$consock->sockport);
sub _SendCommand
{
	my $this = shift;
	my ($cmd,$msg) = @_;
	my $ret = 1;

	$ret = $this->_SetError("Sending command $cmd failed.") unless $this->_SendLine($cmd,defined $msg ? " ".$msg : "");
	return $ret;
}

## receive a line (command). (protocol)
## This function receives data from the ARCv2 connection and
## fills the internal C<__linequeue> and C<__partial>. It returns 
## a line from the internal buffer if there is any. It also handles
## timeouts and "connection closed by foreign host"'s.
##out> true (and the line) if everything worked fine, otherwise false (undef)
##eg> if (my $line = $this->_RecvLine()) { ... }
sub _RecvLine
{
	my $this = shift;

lib/Arc/Connection.pm  view on Meta::CPAN

			$this->{_connection}->close();
			# if timed out, 
			return $this->_SetError("Connection timed out.");
		}
	}
	$this->{__partial} = $partial;
	return shift @{$this->{__linequeue}};
}

## receives an ARCv2 Command. (protocol)
## This function gets a line from C<_RecvLine> and extracts the ARCv2 command and
## the optional command parameter C<_cmdparameter>.
##out> ARCv2 command and true if everything works fine, otherwise false
##eg> while (my $cmd = $this->_RecvCommand()) { ... }
sub _RecvCommand
{
	my $this = shift;

	my $command = undef;
	if (my $line = $this->_RecvLine()) { # Fetch and parse a cmd from queue
		$line =~ s/[\r\n]//g;
		($command,$this->{_cmdparameter}) = $line =~ m/^([A-Z]+)\ ?(.*)?$/;
	}
		
	return $command; # There was an error if undef is return 
}

## process an ARCv2 command. (protocol)
## Process a command by evaling $this->_R$cmd. Also checks if 
## this command was expected now (looks into the $this->{_expectedcmds} array). 
## Used by client and server.
##in> $cmd
##out> true, if ARCv2 command has been in place, otherwise false
##eg> while (my $cmd = $this->_RecvCommand() && $this->_ProcessLine($cmd)) {}
sub _ProcessLine
{
	my $this = shift;
	my $cmd = shift;
	my $ret = 1;

	$this->_Debug("Received Command: $cmd (",@{$this->{_expectedcmds}},")");
	if (grep { $_ eq $cmd } @{$this->{_expectedcmds}} ) {
		$cmd = "_R".$cmd;
		$ret = $this->_SetError("Evaluation of command $cmd failed ($@).") 
			unless eval { $this->$cmd; }
	} else {
		$ret = $this->_SetError("Unexpected command: $cmd");
	}
	return $ret;
}

## send the ARCv2 SASL command. (protocol)
## This function encodes the output from sasl_*_start and sasl_*_step with Base-64 and sends
## it to the other side
##in> $saslstr
##out> true if successful, otherwise false
##eg> $this->_Sasl($sasl->client_start());
sub _Sasl
{
	my ($this,$str) = @_;
	return $this->_SendCommand("SASL",encode_base64($str,""));
}

lib/Arc/Connection.pod  view on Meta::CPAN

=head1 NAME

Arc::Connection - Abstract base class for connection handling for ARCv2

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

This module is part of the module suite ARCv2.

This is the connection module from ARCv2. If we would use C++, we would say
this is an abstract class of an ARCv2 Connection. This class provides common
methods to its derived classes. Such as for authentication and basic ARCv2 
protocols.

lib/Arc/Connection.pod  view on Meta::CPAN

B<Default value>: undef

=item service 

B<Description>: name of the server (for SASL)

B<Default value>: undef

=item timeout 

B<Description>: timeout for all connections (ARCv2 and command) in seconds

B<Default value>: undef

=back 

=over 2

=item logdestination I<inherited from Arc>

B<Description>: Where should all the log output go to ('stderr','syslog')

lib/Arc/Connection.pod  view on Meta::CPAN

=head3 PROTECTED MEMBERS

=over 2

=item _authenticated 

B<Description>: Are we authenticated

=item _cmdclientsock 

B<Description>: IO::Socket for the command connection (encrypted)

B<Default value>: undef

=item _cmdparameter 

B<Description>: parameter after the command

B<Default value>: undef

=item _connected 

B<Description>: are we connected

=item _connection 

B<Description>: IO::Socket for the ARCv2 Connection

B<Default value>: undef

=item _expectedcmds 

B<Description>: array, which ARCv2 protocol commands are allowed to come next

B<Default value>: undef

=item _select 

B<Description>: IO::Select for the ARCv2 Connection

B<Default value>: undef

=item _username 

lib/Arc/Connection.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) I<inherited from Arc>

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/Arc/Connection.pod  view on Meta::CPAN

=over 2

=back 

=head3 PROTECTED METHODS

=over 2

=item _CommandConnection (  ) 

B<Description>: initializes command connection. (protocol)
Starts listen on the Command socket and sends the B<CMDPASV> command.


B<Returns:> true if everything went like expected, otherwise false.


B<Example:>

$this->_CommandConnection();


lib/Arc/Connection.pod  view on Meta::CPAN

B<Returns:> true if successful, otherwise false


B<Example:>

$this->_PrepareAuthentication() || return;


=item _ProcessLine ( $cmd ) 

B<Description>: process an ARCv2 command. (protocol)
Process a command by evaling $this->_R$cmd. Also checks if 
this command was expected now (looks into the $this->{_expectedcmds} array). 
Used by client and server.


B<Returns:> true, if ARCv2 command has been in place, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand() && $this->_ProcessLine($cmd)) {}


=item _ReadWriteBinary ( *locfdin, *locfdout ) 

B<Description>: function for reading and writing on the command connection.
This function is always used by the C<Arc::Connection::Server> to handle 
command data. When calling the C<ProcessCommand> from C<Arc::Connection::Client> 
this function is also used.
Data is read from the local socket resp. pipe and is written encrypted 
to the network socket. The other side reads the data from network socket, 
decrypts it and writes it to its local socket. This function behaves differently on 
client and server sides, when the local or network socket is closed.


B<Returns:> always true


B<Example:>

$this->ReadWriteBinary(*STDIN,*STDOUT);


=item _RecvCommand (  ) 

B<Description>: receives an ARCv2 Command. (protocol)
This function gets a line from C<_RecvLine> and extracts the ARCv2 command and
the optional command parameter C<_cmdparameter>.


B<Returns:> ARCv2 command and true if everything works fine, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand()) { ... }


=item _RecvLine (  ) 

B<Description>: receive a line (command). (protocol)
This function receives data from the ARCv2 connection and
fills the internal C<__linequeue> and C<__partial>. It returns 
a line from the internal buffer if there is any. It also handles
timeouts and "connection closed by foreign host"'s.


B<Returns:> true (and the line) if everything worked fine, otherwise false (undef)


B<Example:>

if (my $line = $this->_RecvLine()) { ... }


=item _Sasl ( $saslstr ) 

B<Description>: send the ARCv2 SASL command. (protocol)
This function encodes the output from sasl_*_start and sasl_*_step with Base-64 and sends
it to the other side


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_Sasl($sasl->client_start());


=item _SendCommand ( $cmd, $parameter ) 

B<Description>: send a command. (protocol)  
Send a command to the ARCv2 socket.


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_SendCommand("CMDPASV",$consock->sockhost.':'.$consock->sockport);


=item _SendLine ( ... (line) ) 

B<Description>: send a line. (protocol)
This function sends a command line to the ARCv2 socket.


B<Returns:> true if writing has succeeded, otherwise false.


B<Example:>

$this->_SendLine($cmd,"test"); 


lib/Arc/Connection/Client.pm  view on Meta::CPAN

sub _InitARC2
{
	my $this = shift;
	@{$this->{_expectedcmds}} = qw(ERR AUTH);
	$this->{_authenticated} = 0;
	return $this->_SendCommand ("ARC/2.".$this->{protocol});
}

## initiate the authentication.
## Tells the server which authtype we want to use.
## Protocol command: AUTHENTICATE [<authtype>]\r\n
##out> true when succesful, otherwise false
##eg> $this->_Authenticate();
sub _Authenticate
{
	my $this = shift;
	@{$this->{_expectedcmds}} = qw(ERR AUTHTYPE);
	return $this->_SendCommand ("AUTHENTICATE",$this->{sasl_mechanism});
}

## initiate the authentication (sasl)
## Creates the sasl object (client_new).
## Client begins always and sends the first SASL challenge
## Protocol command: SASL <base64 encoded SASL output>\r\n
##out> true when succesful, otherwise false
##eg> $this->_StartAuthentication();
sub _StartAuthentication
{
	my $this = shift;

	$this->_PrepareAuthentication() || return;
	
	$this->{__sasl}->callback(
		user => $this->{sasl_cb_user}, 

lib/Arc/Connection/Client.pm  view on Meta::CPAN

	# sasl Context created
	if (!defined $sasl || $sasl->code != 0) {
		return $this->_SetError("creating SASL object failed: ",$sasl->error());
	}
	
	@{$this->{_expectedcmds}} = qw(SASL ERR);
	return $this->_StepAuthentication(1);
}

## another SASL step.
## Response of a SASL command from the server.
## Protocol command: SASL <base64 encoded SASL outout>\r\n
##in> $first_step
##out> true when succesful, otherwise false
##eg> return $this->_StepAuthentication(1);
sub _StepAuthentication
{
	my $this = shift;
	my $first = shift;
	my $sasl = $this->{_sasl};
	my $ret = 0;
	my $str;

lib/Arc/Connection/Client.pm  view on Meta::CPAN

		} else {
			$ret = $this->_Sasl($str);
		}
	} else {
		$this->Quit();
		$ret = $this->_SetError("SASL: Negotiation failed. User is not authenticated. SASL error: (",$sasl->code,") ",$sasl->error);
	}
	return $ret
}

## send an ARCv2 command request
## Protocol command: CMD <cmd> <cmdparameter>\r\n
##in> ... (cmd and parameter)
##out> true when succesful, otherwise false
##eg> $this->_Cmd ("whoami");
sub _Cmd
{
	my $this = shift;
	my $str = join " ",@_;
	$str =~ s/[\r\n]//g;
	return $this->_SetError("Empty command won't be sent.") unless length $str;
	@{$this->{_expectedcmds}} = qw(ERR CMDPASV DONE);
	return $this->_SendCommand("CMD",$str);
}

# The _R subs are processing a server response, call resp. subs and set the expectedcmds array approp.
## parses the AUTH <list of SASL mech>\r\n, sent by the server
sub _RAUTH
{
	my $this = shift;
	@{$this->{server_sasl_mechanisms}} = split(',',$this->{_cmdparameter});

lib/Arc/Connection/Client.pm  view on Meta::CPAN

## parses the SASL <base64 encoded SASL string>\r\n, sent by the server.
## Sasl response from the server
sub _RSASL
{
	my $this = shift;
	return $this->_SetError("SASL Negotiation failed.") unless ($this->_StepAuthentication(0));
	return 1;
}

## parses the ERR <msg>\r\n, sent by the server.
## Server command, which reports an server-side error
sub _RERR
{
	my $this = shift;

	$this->_SetError("Server ERROR:",$this->{_cmdparameter});
	return 1;
}

## parses the CMDERR <msg>\r\n, sent by the server.
## Command specific error, which reports an error during the command
sub _RCMDERR
{
	my $this = shift;
	$this->_SetError("Command ERROR:",$this->{_cmdparameter});
	return 1;
}

## parses CMDPASV <host:port>\r\n, sent by the server.
## Establish the encrypted command connection.
sub _RCMDPASV
{
	my $this = shift;
	$this->Log(LOG_SIDE,"Try to connect to:",$this->{_cmdparameter});
	
	@{$this->{_expectedcmds}} = qw(ERR DONE CMDERR);

	return if defined $this->{_cmdclientsock};

	my ($host,$port) = split(/:/,$this->{_cmdparameter});

lib/Arc/Connection/Client.pm  view on Meta::CPAN

	$this->{_cmdclientsock} = new IO::Socket::INET(
		PeerAddr => $host,
		PeerPort => $port,
		Type => SOCK_STREAM,
	) || return $this->_SetError("Passive Connection failed."); 
	
	return 1;
}

## parses DONE\r\n, sent by the server.
## This is received when a command is done.
sub _RDONE
{
	my $this = shift;
	@{$this->{_exceptedcmds}} = qw(ERR CMD);
	return 1;
}

## start an ARCv2 session.
## This function which will change the status of the connection into a
## authenticated status. Users have to call this function
## to be able to run ARCv2 commands afterwards.
##out> true if authentication was successful, otherwise false.
##eg> if ($arc->StartSession()) { .. }
sub StartSession
{
	my $this = shift;
	return $this->_SetError("There is already a command running.") if $this->IsConnected();
	return $this->_SetError("Connection to host ",$this->{server},":",$this->{port}," failed") unless $this->_Connect();
	$this->_InitARC2();

	while (!$this->{_error} && ($this->{_authenticated} == 0) && (my $cmd = $this->_RecvCommand())) {
		last unless $this->_ProcessLine($cmd);
	}
	return !$this->{_error} && $this->{_authenticated};
}

## ends the connection.
## Tells the server that we want to end the conversation. (Userlevel)
## Protocol command: QUIT\r\n
##out> always true
##eg> $arc->Quit();
sub Quit
{
	my $this = shift;
	$this->_SendCommand("QUIT");
	$this->{_connection}->close();
	$this->{_connected} = 0;
	$this->{_expectedcmds} = qw();
	return 1;
}

## process a command.
## This function runs a command with STDIN and STDOUT as clients 
## in- and output control.
##in> ... (command and its parameters)
##out> true if successful, false if not. (IsError is set appropriatly)
##eg> $arc->ProcessCommand("whoami");
sub ProcessCommand
{
	my $this = shift;

	return unless $this->CommandStart(@_);

	STDOUT->autoflush(1);
	$this->_ReadWriteBinary(*STDIN,*STDOUT);

	return $this->CommandEnd();
}

## start an ARCv2 command
## This function starts the given ARCv2 Command and enables the Command* functions.
##in> ... (command and its parameters)
##out> true if successful, false if not. (IsError is set appropriatly)
##eg> if ($arc->CommandStart()) { ... }
sub CommandStart
{
	my $this = shift;
	return $this->_SetError("You are not authenticated.") unless $this->{_authenticated};
	return $this->_SetError("Already running a command.") if defined $this->{_cmdclientsock};
	return unless @_;
	return unless $this->_Cmd(@_);

	while (!$this->{_error} && (not defined $this->{_cmdclientsock}) && (my $cmd = $this->_RecvCommand()) ) {
		$this->_ProcessLine($cmd);
		last if $cmd eq "DONE";
	}
	return 1 if defined $this->{_cmdclientsock};
	return;
}

## write something to the command.
## Write something to the standard input of the command started by C<CommandStart>.
##in> ... (data)
##out> true if successful, false if not. (IsError is set appropriatly)
##eg> last unless $this->CommandWrite();
sub CommandWrite
{
	my $this = shift;
	return $this->_SetError("There is no command running.") unless defined $this->{_cmdclientsock};
	return unless @_;

	my $str = join("",@_);
	$str = $this->{_sasl}->encode($str);

	return $this->{_cmdclientsock}->syswrite($str);
}

## close the write part of the netsock.
## This function closes the write-part of the command connection.
##out> true if successful, false if not. (IsError is set appropriatly)
##eg> last unless $arc->CommandEOF();
sub CommandEOF
{
	my $this = shift;
	return $this->_SetError("There is no command running.") unless defined $this->{_cmdclientsock};

	return shutdown($this->{_cmdclientsock},1);
}

## read data from the Command connection.
##out> if successful the received data is returned, otherwise false.
##eg> while (my $data = $arc->CommandRead()) { ... }
sub CommandRead
{
	my $this = shift;
	return $this->_SetError("There is no command running.") unless defined $this->{_cmdclientsock};

	my $sel = new IO::Select ( $this->{_cmdclientsock} );
	my $buf;
	while ($sel->can_read($this->{timeout})) {
		return unless $this->{_cmdclientsock}->sysread($buf,1024);
		$buf = $this->{_sasl}->decode($buf);
		next unless $buf; # SASL incomplete decode
		return $buf;
	}
	return;
}

## end the command on the server side.
## Closes the command connection and ends the command.
##out> true if successful, false if not. (IsError is set appropriatly)
##eg> $arc->CommandEnd();
sub CommandEnd
{
	my $this = shift;
	return $this->_SetError("There is no command running.") unless defined $this->{_cmdclientsock};

	if ($this->{protocol} == 1) {
# encrypted protocol and command connection, don't lose synchronized sasl_de/encode
		$this->CommandEOF();
		while ($_ = $this->CommandRead()) { $this->_Debug("read text: ".$_); };
	}		

	$this->{_cmdclientsock}->close();
	$this->{_cmdclientsock} = undef;

	while (my $cmd = $this->_RecvCommand()) {
		last unless $this->_ProcessLine($cmd);
		last if $cmd eq "DONE";

lib/Arc/Connection/Client.pod  view on Meta::CPAN

=head1 NAME

Arc::Connection::Client - Client class for ARCv2

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

Arc::Connection::Client - Client class for ARCv2

 my $arc = new Arc::Connection::Client(
  server => "hyade11",
  port => 4242,
  timeout => 30,

lib/Arc/Connection/Client.pod  view on Meta::CPAN

=over 2

=item service I<inherited from Arc::Connection>

B<Description>: name of the server (for SASL)

B<Default value>: undef

=item timeout I<inherited from Arc::Connection>

B<Description>: timeout for all connections (ARCv2 and command) in seconds

B<Default value>: undef

=back 

=over 2

=item loglevel I<inherited from Arc>

B<Description>: loglevel is combination of bits (1=AUTH,2=USER,4=ERR,8=CMDDEBUG,16=VERBSIDE,32=DEBUG) see _Log method

lib/Arc/Connection/Client.pod  view on Meta::CPAN

=head3 PROTECTED MEMBERS

=over 2

=item _authenticated I<inherited from Arc::Connection>

B<Description>: Are we authenticated

=item _cmdclientsock I<inherited from Arc::Connection>

B<Description>: IO::Socket for the command connection (encrypted)

B<Default value>: undef

=item _cmdparameter I<inherited from Arc::Connection>

B<Description>: parameter after the command

B<Default value>: undef

=item _connected I<inherited from Arc::Connection>

B<Description>: are we connected

=item _connection I<inherited from Arc::Connection>

B<Description>: IO::Socket for the ARCv2 Connection

B<Default value>: undef

=item _expectedcmds I<inherited from Arc::Connection>

B<Description>: array, which ARCv2 protocol commands are allowed to come next

B<Default value>: undef

=item _select I<inherited from Arc::Connection>

B<Description>: IO::Select for the ARCv2 Connection

B<Default value>: undef

=item _username I<inherited from Arc::Connection>

lib/Arc/Connection/Client.pod  view on Meta::CPAN

=head3 PRIVATE MEMBERS

=head1 Class METHODS

=head3 PUBLIC METHODS

=over 2

=item CommandEnd (  ) 

B<Description>: end the command on the server side.
Closes the command connection and ends the command.


B<Returns:> true if successful, false if not. (IsError is set appropriatly)


B<Example:>

$arc->CommandEnd();


=item CommandEOF (  ) 

B<Description>: close the write part of the netsock.
This function closes the write-part of the command connection.


B<Returns:> true if successful, false if not. (IsError is set appropriatly)


B<Example:>

last unless $arc->CommandEOF();


lib/Arc/Connection/Client.pod  view on Meta::CPAN



B<Returns:> if successful the received data is returned, otherwise false.


B<Example:>

while (my $data = $arc->CommandRead()) { ... }


=item CommandStart ( ... (command and its parameters) ) 

B<Description>: start an ARCv2 command
This function starts the given ARCv2 Command and enables the Command* functions.


B<Returns:> true if successful, false if not. (IsError is set appropriatly)


B<Example:>

if ($arc->CommandStart()) { ... }


=item CommandWrite ( ... (data) ) 

B<Description>: write something to the command.
Write something to the standard input of the command started by C<CommandStart>.


B<Returns:> true if successful, false if not. (IsError is set appropriatly)


B<Example:>

last unless $this->CommandWrite();


=item ProcessCommand ( ... (command and its parameters) ) 

B<Description>: process a command.
This function runs a command with STDIN and STDOUT as clients 
in- and output control.


B<Returns:> true if successful, false if not. (IsError is set appropriatly)


B<Example:>

$arc->ProcessCommand("whoami");


=item Quit (  ) 

B<Description>: ends the connection.
Tells the server that we want to end the conversation. (Userlevel)
Protocol command: QUIT\r\n


B<Returns:> always true


B<Example:>

$arc->Quit();


=item StartSession (  ) 

B<Description>: start an ARCv2 session.
This function which will change the status of the connection into a
authenticated status. Users have to call this function
to be able to run ARCv2 commands afterwards.


B<Returns:> true if authentication was successful, otherwise false.


B<Example:>

if ($arc->StartSession()) { .. }


lib/Arc/Connection/Client.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) I<inherited from Arc>

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/Arc/Connection/Client.pod  view on Meta::CPAN

=back 

=head3 PROTECTED METHODS

=over 2

=item _Authenticate (  ) 

B<Description>: initiate the authentication.
Tells the server which authtype we want to use.
Protocol command: AUTHENTICATE [<authtype>]\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Authenticate();


=item _Cmd ( ... (cmd and parameter) ) 

B<Description>: send an ARCv2 command request
Protocol command: CMD <cmd> <cmdparameter>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Cmd ("whoami");


lib/Arc/Connection/Client.pod  view on Meta::CPAN


=item _RAUTHTYPE (  ) 

B<Description>: parses the AUTHTYPE <SASL mech>\r\n, sent by the server.
Which SASL mech the server will use.


=item _RCMDERR (  ) 

B<Description>: parses the CMDERR <msg>\r\n, sent by the server.
Command specific error, which reports an error during the command


=item _RCMDPASV (  ) 

B<Description>: parses CMDPASV <host:port>\r\n, sent by the server.
Establish the encrypted command connection.


=item _RDONE (  ) 

B<Description>: parses DONE\r\n, sent by the server.
This is received when a command is done.


=item _RERR (  ) 

B<Description>: parses the ERR <msg>\r\n, sent by the server.
Server command, which reports an server-side error


=item _RSASL (  ) 

B<Description>: parses the SASL <base64 encoded SASL string>\r\n, sent by the server.
Sasl response from the server


=item _StartAuthentication (  ) 

B<Description>: initiate the authentication (sasl)
Creates the sasl object (client_new).
Client begins always and sends the first SASL challenge
Protocol command: SASL <base64 encoded SASL output>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_StartAuthentication();


=item _StepAuthentication ( $first_step ) 

B<Description>: another SASL step.
Response of a SASL command from the server.
Protocol command: SASL <base64 encoded SASL outout>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

return $this->_StepAuthentication(1);


=back 

=over 2

=item _CommandConnection (  ) I<inherited from Arc::Connection>

B<Description>: initializes command connection. (protocol)
Starts listen on the Command socket and sends the B<CMDPASV> command.


B<Returns:> true if everything went like expected, otherwise false.


B<Example:>

$this->_CommandConnection();


lib/Arc/Connection/Client.pod  view on Meta::CPAN

B<Returns:> true if successful, otherwise false


B<Example:>

$this->_PrepareAuthentication() || return;


=item _ProcessLine ( $cmd ) I<inherited from Arc::Connection>

B<Description>: process an ARCv2 command. (protocol)
Process a command by evaling $this->_R$cmd. Also checks if 
this command was expected now (looks into the $this->{_expectedcmds} array). 
Used by client and server.


B<Returns:> true, if ARCv2 command has been in place, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand() && $this->_ProcessLine($cmd)) {}


=item _ReadWriteBinary ( *locfdin, *locfdout ) I<inherited from Arc::Connection>

B<Description>: function for reading and writing on the command connection.
This function is always used by the C<Arc::Connection::Server> to handle 
command data. When calling the C<ProcessCommand> from C<Arc::Connection::Client> 
this function is also used.
Data is read from the local socket resp. pipe and is written encrypted 
to the network socket. The other side reads the data from network socket, 
decrypts it and writes it to its local socket. This function behaves differently on 
client and server sides, when the local or network socket is closed.


B<Returns:> always true


B<Example:>

$this->ReadWriteBinary(*STDIN,*STDOUT);


=item _RecvCommand (  ) I<inherited from Arc::Connection>

B<Description>: receives an ARCv2 Command. (protocol)
This function gets a line from C<_RecvLine> and extracts the ARCv2 command and
the optional command parameter C<_cmdparameter>.


B<Returns:> ARCv2 command and true if everything works fine, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand()) { ... }


=item _RecvLine (  ) I<inherited from Arc::Connection>

B<Description>: receive a line (command). (protocol)
This function receives data from the ARCv2 connection and
fills the internal C<__linequeue> and C<__partial>. It returns 
a line from the internal buffer if there is any. It also handles
timeouts and "connection closed by foreign host"'s.


B<Returns:> true (and the line) if everything worked fine, otherwise false (undef)


B<Example:>

if (my $line = $this->_RecvLine()) { ... }


=item _Sasl ( $saslstr ) I<inherited from Arc::Connection>

B<Description>: send the ARCv2 SASL command. (protocol)
This function encodes the output from sasl_*_start and sasl_*_step with Base-64 and sends
it to the other side


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_Sasl($sasl->client_start());


=item _SendCommand ( $cmd, $parameter ) I<inherited from Arc::Connection>

B<Description>: send a command. (protocol)  
Send a command to the ARCv2 socket.


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_SendCommand("CMDPASV",$consock->sockhost.':'.$consock->sockport);


=item _SendLine ( ... (line) ) I<inherited from Arc::Connection>

B<Description>: send a line. (protocol)
This function sends a command line to the ARCv2 socket.


B<Returns:> true if writing has succeeded, otherwise false.


B<Example:>

$this->_SendLine($cmd,"test"); 


lib/Arc/Connection/Server.pm  view on Meta::CPAN

{
	my $this = shift;
	return { %{$this->SUPER::members},
		_realm => "",             # Name of the SASL realm, if the user is from the default realm, this is empty
		logfileprefix => "server",

		sasl_cb_getsecret => "",  # Callback for SASL (if PLAIN (or equal) mechanisms are used). See Authen::SASL(::Cyrus).
		sasl_cb_checkpass => 0,   # Callback for SASL (if PLAIN (or equal) mechanisms are used). See Authen::SASL(::Cyrus).
		sasl_mechanisms => undef, # array of allowed SASL mechanisms

		commands => undef,        # hash of assignment between B<Command Name> and B<Command Class>. See L<Arc::Command>
	};
}

sub _Init
{
	my $this = shift;

	return unless $this->SUPER::_Init(@_);

	# sasl_mechanisms
	return $this->_SetError("No SASL mechanisms given.")
		unless defined $this->{sasl_mechanisms};

	# commands
	return $this->_SetError("No ARCv2 commands given. There is no reason the run ARCv2.")
		unless defined $this->{commands};
}

## Callback function to canonicalize the username (SASL)
## see Authen::SASL(::Cyrus) for parameter list and how to use.
sub _CBCanonUser
{
	my ($this,$type,$realm,$maxlen,$user) = @_;
	return $user;
}

## send the available SASL mechanisms.
## Protocol command: AUTH <comma-seperated list of SASL mechansims>\r\n
##out> true when succesful, otherwise false
##eg> $this->_Auth();
sub _Auth
{
	my $this = shift;

	@{$this->{_expectedcmds}} = qw(QUIT AUTHENTICATE);
	return $this->_SendCommand("AUTH",join (",",@{$this->{sasl_mechanisms}}));
}

## send an error msg to client (Server error).
## Protocol command: ERR <msg>\r\n
##out> true when succesful, otherwise false
##eg> $this->_Error("failure.");
sub _Error
{
	my $this = shift;
	return $this->_SendCommand("ERR",join("",@_));
}

## send a command error msg to client.
## Protocol command: CMDERR <msg>\r\n
##out> true when succesful, otherwise false
##eg> $this->_CmdError("failure.");
sub _CmdError
{
	my $this = shift;
	return $this->_SendCommand("CMDERR",join("",@_));
}

## command is ready.
## When the ARCv2 command is ready with its work, the server
## sends the DONE command on the control connection.
## Protocol command: DONE\r\n
##out> true when succesful, otherwise false
##eg> $this->_Done();
sub _Done
{
	my $this = shift;
	return $this->_SendCommand("DONE");
}

## tell the client, which SASL mechanism is used.
## Protocol command: AUTHTYPE <SASL mechansism>\r\n
##out> true when succesful, otherwise false
##eg> $this->_Authtype();
sub _Authtype
{
	my $this = shift;
	@{$this->{_expectedcmds}} = qw(QUIT SASL);
	return $this->_SendCommand("AUTHTYPE",$this->{_saslmech});
}

## Creates the sasl object (server_new)
## and sends the first sasl challenge/response.
## Protocol command: SASL <base64 encoded SASL output>\r\n
##out> true when succesful, otherwise false
##eg> $this->_StartAuthentication();
sub _StartAuthentication
{
	my $this = shift;

	$this->_PrepareAuthentication() || return;

	# Setting the Callback for getting the username
	# This has to happen just before the object-creation of cyrus sasl

lib/Arc/Connection/Server.pm  view on Meta::CPAN

	if ((!defined $sasl) or ($sasl->code != 0)) {
		return $this->_SetError("SASL: ",$sasl->error());
	}

	$this->_Debug("Available mechanisms. ",$sasl->listmech("","|",""));

	return $this->_StepAuthentication(1);
}

## Another SASL step
## Response of a SASL command from the client
## Protocol command: SASL <base64 encoded SASL outout>\r\n
##in> bool $first_step
##out> true when succesful, otherwise false
##eg> $this->_StepAuthentication(1);
sub _StepAuthentication
{
	my $this = shift;
	my $first = shift;
	my $sasl = $this->{_sasl};
	my $ret = 0;
	my $str;

lib/Arc/Connection/Server.pm  view on Meta::CPAN

	}
	return $ret;
}

## See source code for this method. /dev/null for unwanted output.
sub tonne {

}

## parses the CMD <cmd>\r\n, sent by the client.
## check if the command exists, prepares the command connection, executes the command and
## does cleanups after execution.
sub _RCMD
{
	my $this = shift;

	my ($cmd,$para) = split(/\s+/,$this->{_cmdparameter},2);
	$this->_Error("Command not found.") unless defined $cmd;

	my $perlcmd = $this->{commands}->{$cmd};
my $reason = $this->_CheckCmd($cmd, $perlcmd);

	if (defined $reason) {
		$this->Log(LOG_USER, "Command '$cmd' requested by user '".$this->{_username}.
		"' not ok", $reason ? ": $reason" : "");
		$this->_Error("Command $cmd not ok", $reason ? ": $reason" : "");
	} elsif( !$this->{_error} && defined $perlcmd ) {
		$this->Log(LOG_USER,"Command '$cmd' requested by user '".$this->{_username}.
			"' mapped to '$perlcmd'",$para ? "with parameters '$para'" : "");
		if (eval "require $perlcmd;") {

			my $in =  new IO::Pipe || return $this->_SetError("Could not create in-Pipe");
			my $out = new IO::Pipe || return $this->_SetError("Could not create out-Pipe");
			my $err = new IO::Pipe || return $this->_SetError("Could not create err-Pipe");

			my $oldsigchld = $SIG{CHLD};
			$SIG{CHLD} = 'IGNORE';

			my $cmdpid = fork();
			if ($cmdpid == 0) { # Child
				$this->{logfileprefix} = "commandchild";

# prepare environment for the command
				$in->writer(); $out->reader(); $err->writer();
				open STDIN, "<&", $out;
				open STDOUT, ">&", $in;
				open STDERR, ">&", $err;

				my @a = $this->_SplitCmdArgs($para);
				my ($ret, $cmderr) = $this->_RunCmd($cmd, $perlcmd, \@a);

				if ($cmderr) {
					$ret = 1;
					$cmderr =~ s/\r//g; $cmderr =~ s/\n/ /g; $cmderr =~ s/ +/ /g;
					print $err $cmderr;
				}
				close $in; close $out; close $err;

				exit $ret;
			} elsif ($cmdpid) {

				$this->Log(LOG_SIDE,"Awaiting command connection.");
				$this->_CommandConnection();

				# check that the connecting host is really the host we are expecting to be.
				my ($peerport,$peeraddr) = sockaddr_in($this->{_cmdclientsock}->peername);
				$peeraddr = inet_ntoa($peeraddr);

				if ($peeraddr eq $this->{_connection}->peerhost) {

					$this->Log(LOG_CMD,"Command connection established.");

lib/Arc/Connection/Server.pm  view on Meta::CPAN


					$out->autoflush(1);
					$this->_ReadWriteBinary($in,$out);

					$this->{_cmdclientsock}->close();

					$this->Log(LOG_CMD,"Command done.");

					while (<$err>) {
						$this->_CmdError($_);
#						$this->_Debug("command errors: $_");
					}

					close $in; close $out; close $err;
				} else {
					$this->_SetError("Unknown host wanted ".
						"to use our command connection. ($peeraddr)");
				}
				wait();
			} else {
				$this->_SetError("Fork error.");
			}
			$SIG{CHLD} = $oldsigchld;
		} else {
			my $e = $@;
			$this->Log(LOG_CMD,"$perlcmd: ",$e);
			$this->_Error("Command $perlcmd not found or error: ".$e);

lib/Arc/Connection/Server.pm  view on Meta::CPAN

}

sub _RunCmd
{
	my $this = shift;
	my ($cmd, $perlcmd, $argref) = @_;

	my $cmderr;
	my $ret = eval {
		my $object = new $perlcmd (
			_commands => $this->{commands},
			_username => $this->{_username},
			_realm    => $this->{_realm},
			_mech     => $this->{_saslmech},
			_peeraddr => $this->{_connection}->peerhost,
			_peerport => $this->{_connection}->peerport,
			_peername => $this->{_connection}->peername,
			_cmd => $cmd,
			logfileprefix => "command",
		);
		$object->Execute(@{ $argref });
		$cmderr = $object->IsError();
		return 0;
	};

	$ret = 2 unless defined($ret);
	$cmderr .= " ".$@ if $@;

	return ($ret, $cmderr);
}

## does nothing, placeholder for QUIT\r\n command, sent by the client.
sub _RQUIT
{
	my $this = shift;
	return 1;
}

## Public function, gets the clientsocket (from Arc::Server) and handles it.
## Handles a connection (main loop).
##in> $clientsock (IO::Socket)
##out> true on success, otherwise false

lib/Arc/Connection/Server.pod  view on Meta::CPAN

=head1 NAME

Arc::Connection::Server - Class to handle one connection on the server side 

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

Arc::Connection::Server - Server handle for ARCv2.
This class is called by Arc::Server for each incoming connection.


=head1 Class VARIABLES

=head3 PUBLIC MEMBERS

=over 2

=item commands 

B<Description>: hash of assignment between B<Command Name> and B<Command Class>. See L<Arc::Command>

B<Default value>: undef

=item logfileprefix I<reimplemented from Arc>

B<Default value>: "server"

=item sasl_cb_checkpass 

lib/Arc/Connection/Server.pod  view on Meta::CPAN

B<Default value>: undef

=item service I<inherited from Arc::Connection>

B<Description>: name of the server (for SASL)

B<Default value>: undef

=item timeout I<inherited from Arc::Connection>

B<Description>: timeout for all connections (ARCv2 and command) in seconds

B<Default value>: undef

=back 

=over 2

=item logdestination I<inherited from Arc>

B<Description>: Where should all the log output go to ('stderr','syslog')

lib/Arc/Connection/Server.pod  view on Meta::CPAN

=back 

=over 2

=item _authenticated I<inherited from Arc::Connection>

B<Description>: Are we authenticated

=item _cmdclientsock I<inherited from Arc::Connection>

B<Description>: IO::Socket for the command connection (encrypted)

B<Default value>: undef

=item _cmdparameter I<inherited from Arc::Connection>

B<Description>: parameter after the command

B<Default value>: undef

=item _connected I<inherited from Arc::Connection>

B<Description>: are we connected

=item _connection I<inherited from Arc::Connection>

B<Description>: IO::Socket for the ARCv2 Connection

B<Default value>: undef

=item _expectedcmds I<inherited from Arc::Connection>

B<Description>: array, which ARCv2 protocol commands are allowed to come next

B<Default value>: undef

=item _select I<inherited from Arc::Connection>

B<Description>: IO::Select for the ARCv2 Connection

B<Default value>: undef

=item _username I<inherited from Arc::Connection>

lib/Arc/Connection/Server.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) I<inherited from Arc>

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/Arc/Connection/Server.pod  view on Meta::CPAN


=back 

=head3 PROTECTED METHODS

=over 2

=item _Auth (  ) 

B<Description>: send the available SASL mechanisms.
Protocol command: AUTH <comma-seperated list of SASL mechansims>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Auth();


=item _Authtype (  ) 

B<Description>: tell the client, which SASL mechanism is used.
Protocol command: AUTHTYPE <SASL mechansism>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Authtype();


=item _CBCanonUser (  ) 

B<Description>: Callback function to canonicalize the username (SASL)
see Authen::SASL(::Cyrus) for parameter list and how to use.


=item _CheckCmd (  ) 

=item _CmdError (  ) 

B<Description>: send a command error msg to client.
Protocol command: CMDERR <msg>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_CmdError("failure.");


=item _Done (  ) 

B<Description>: command is ready.
When the ARCv2 command is ready with its work, the server
sends the DONE command on the control connection.
Protocol command: DONE\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Done();


=item _Error (  ) 

B<Description>: send an error msg to client (Server error).
Protocol command: ERR <msg>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_Error("failure.");


lib/Arc/Connection/Server.pod  view on Meta::CPAN

=item _RAUTHENTICATE (  ) 

B<Description>: parses the AUTHENTICATE[ <SASL mech>]\r\n, sent by the client.
Checks if the demanded SASL mechanism is allowed and returns the
selected mechanism.


=item _RCMD (  ) 

B<Description>: parses the CMD <cmd>\r\n, sent by the client.
check if the command exists, prepares the command connection, executes the command and
does cleanups after execution.


=item _RQUIT (  ) 

B<Description>: does nothing, placeholder for QUIT\r\n command, sent by the client.


=item _RSASL (  ) 

B<Description>: parses the SASL <base64 encoded SASL string>\r\n, sent by the client.
Sasl challenge/response from the client


=item _RunCmd (  ) 

=item _SplitCmdArgs (  ) 

=item _StartAuthentication (  ) 

B<Description>: Creates the sasl object (server_new)
and sends the first sasl challenge/response.
Protocol command: SASL <base64 encoded SASL output>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_StartAuthentication();


=item _StepAuthentication ( bool $first_step ) 

B<Description>: Another SASL step
Response of a SASL command from the client
Protocol command: SASL <base64 encoded SASL outout>\r\n


B<Returns:> true when succesful, otherwise false


B<Example:>

$this->_StepAuthentication(1);


=back 

=over 2

=item _CommandConnection (  ) I<inherited from Arc::Connection>

B<Description>: initializes command connection. (protocol)
Starts listen on the Command socket and sends the B<CMDPASV> command.


B<Returns:> true if everything went like expected, otherwise false.


B<Example:>

$this->_CommandConnection();


lib/Arc/Connection/Server.pod  view on Meta::CPAN

B<Returns:> true if successful, otherwise false


B<Example:>

$this->_PrepareAuthentication() || return;


=item _ProcessLine ( $cmd ) I<inherited from Arc::Connection>

B<Description>: process an ARCv2 command. (protocol)
Process a command by evaling $this->_R$cmd. Also checks if 
this command was expected now (looks into the $this->{_expectedcmds} array). 
Used by client and server.


B<Returns:> true, if ARCv2 command has been in place, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand() && $this->_ProcessLine($cmd)) {}


=item _ReadWriteBinary ( *locfdin, *locfdout ) I<inherited from Arc::Connection>

B<Description>: function for reading and writing on the command connection.
This function is always used by the C<Arc::Connection::Server> to handle 
command data. When calling the C<ProcessCommand> from C<Arc::Connection::Client> 
this function is also used.
Data is read from the local socket resp. pipe and is written encrypted 
to the network socket. The other side reads the data from network socket, 
decrypts it and writes it to its local socket. This function behaves differently on 
client and server sides, when the local or network socket is closed.


B<Returns:> always true


B<Example:>

$this->ReadWriteBinary(*STDIN,*STDOUT);


=item _RecvCommand (  ) I<inherited from Arc::Connection>

B<Description>: receives an ARCv2 Command. (protocol)
This function gets a line from C<_RecvLine> and extracts the ARCv2 command and
the optional command parameter C<_cmdparameter>.


B<Returns:> ARCv2 command and true if everything works fine, otherwise false


B<Example:>

while (my $cmd = $this->_RecvCommand()) { ... }


=item _RecvLine (  ) I<inherited from Arc::Connection>

B<Description>: receive a line (command). (protocol)
This function receives data from the ARCv2 connection and
fills the internal C<__linequeue> and C<__partial>. It returns 
a line from the internal buffer if there is any. It also handles
timeouts and "connection closed by foreign host"'s.


B<Returns:> true (and the line) if everything worked fine, otherwise false (undef)


B<Example:>

if (my $line = $this->_RecvLine()) { ... }


=item _Sasl ( $saslstr ) I<inherited from Arc::Connection>

B<Description>: send the ARCv2 SASL command. (protocol)
This function encodes the output from sasl_*_start and sasl_*_step with Base-64 and sends
it to the other side


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_Sasl($sasl->client_start());


=item _SendCommand ( $cmd, $parameter ) I<inherited from Arc::Connection>

B<Description>: send a command. (protocol)  
Send a command to the ARCv2 socket.


B<Returns:> true if successful, otherwise false


B<Example:>

$this->_SendCommand("CMDPASV",$consock->sockhost.':'.$consock->sockport);


=item _SendLine ( ... (line) ) I<inherited from Arc::Connection>

B<Description>: send a line. (protocol)
This function sends a command line to the ARCv2 socket.


B<Returns:> true if writing has succeeded, otherwise false.


B<Example:>

$this->_SendLine($cmd,"test"); 


lib/Arc/Server.pm  view on Meta::CPAN

			server => undef,        # attributes for Net::Server::PreFork
	};
}

sub _Init
{
	my $this = shift;

	return unless $this->SUPER::_Init(@_);

	return $this->_SetError("You have to specify at least the SASL mechs and the commands you want to run, to start the ARCv2 Server.")
		unless $this->{connection_vars};

	unless (defined $this->{server}->{host}) {
		$this->Log(LOG_SIDE,"No host (listenaddress) specified, falling back to all addresses (0).");
		$this->{server}->{host} = 0;
	}

	unless (defined $this->{server}->{port}) {
		$this->Log(LOG_SIDE,"No port specified, falling back to standard port $Arc::DefaultPort.");
		$this->{server}->{port} = [$Arc::DefaultPort];

lib/Arc/Server.pod  view on Meta::CPAN

=head1 NAME

Arc::Server - Class for the standalone server for ARCv2

=head1 DESCRIPTION

ARC allows non-privileged users to run privileged commands on the server.
The server decides if the user is allowed to run this command through ACL.

This file is a part of the Perl ARCv2 module suite. ARCv2 is a 
rewrite of ARC by R.Toebbicke, CERN, Switzerland in Perl. 

=head1 ABSTRACT

From ARC by R. Toebbicke, modified by me:
User requests are shipped from a client machine to a server using a
SASL-authenticated socket connection. The purpose is to convey
requests such as privileged commands (e.g. AFS, Crontab) to be executed on the
server under appropriate privileges. Given that all privileges are
confined to the server and the server can be programmed as to filter and
check the command to be executed, the client machine can be less trusted
than the server.

Because ARC-v1-Commands are written in perl anyway, implementing the client/server
in perl makes sense. Platform-independence and "easy-to-read" source code are welcome
too. This package provides two perl command line scripts (arcx, arcxd). They can
be used for working with the ARC server from the command line, resp. to start the
server.

=head1 SYNOPSIS

Arc::Server - Class for the standalone server for ARCv2

 my $arc = new Arc::Server(
  port => [4242],
  loglevel => 7,
  logdestination => "stderr",
  daemonize => 0,
  connection_type => "Arc::Connection::Server",
  connection_vars => {
   loglevel => 7,
   logdestination => 'syslog',
   timeout => 30,
   sasl_mechanisms => ["GSSAPI","KERBEROS_V4","PLAIN"],
   sasl_cb_getsecret => &getsecret,
   sasl_cb_checkpass => &checkpass,
   commands => {
    'whoami' => 'Arc::Command::Whoami,
    'uptime' => 'Arc::Command::Uptime,
   }
   service => "arc",
  }
 );

 if (my $m = $arc->IsError()) {
  die $m;
 }

lib/Arc/Server.pod  view on Meta::CPAN


unless (my $err = $arc->IsError()) { .. } else { print STDERR $err; }


=item Log ( $facility, ... (message) ) I<inherited from Arc>

B<Description>: Log function.
Logs messages to 'logdestination' if 'loglevel' is is set appropriatly.
loglevel behaviour has changed in the 1.0 release of ARCv2, the "Arc"-class can export
LOG_AUTH (authentication information), LOG_USER (connection information), LOG_ERR (errors), 
LOG_CMD (ARCv2 addition internal command information), LOG_SIDE (verbose client/server-specific
information), LOG_DEBUG (verbose debug information). It possible to combine the 
levels with or (resp. +) to allow a message to appear when not all loglevels are 
requested by the user.
Commonly used for logging errors from application level.


B<Returns:> always false


B<Example:>

lib/arcx.pod  view on Meta::CPAN

=head1 NAME

arcx - ARCv2 client command line interface 

=head1 DESCRIPTION

This file is a basic command line interface for the ARCv2.

=head1 SYNOPSIS

The command line interface arcx:

=over 4

=item arcx 

Connect to the default host, on the default port and start the interactive 
ARC-shell (Term::ReadLine).

=item arcx -h arcserver -p 1234 vos release scripts

Connection arcserver:1234 and run the ARCv2 command "vos" with the
parameters "release scripts"

=item cat /etc/passwd | arcx put /default/etc/passwd

Pipe the content of /etc/passwd through the encrypted connection and let
the server write the content to /default/etc/passwd.

=item arcx get /default/etc/passwd > /etc/passwd

Read the /default/etc/passwd on the server machine and write it locally
to /etc/passwd.

=back

=head1 USAGE

As usual a command line interface has some parameters to influence the behaviour.

The scheme looks like this:

arcx [-h <hostname>] [-p <port>] [-l <loglevel] [-L <logdestination] [-n] [-v] [-S <service>] [-F -f <history>] [-u|-U <username>] [-a|-A <authname>] [-w|-W <password>] [-s <mech>] [-t <timeout in sec>] [-r <string>] [command [command-arguments]]

=head2 Parameter

=over 4

=item -h <hostname>

The hostname, where the ARCv2 server is running. If no -h option is given, arcx will use the one chosen at compile time ($Arc::DefaultHost).

=item -p <port>

lib/arcx.pod  view on Meta::CPAN

=item -v

The verbose option. If this option is set, arcx is verbose in its context. This option does not influence the ARCv2 object. Use -l and -L for it.

=item -n

Do nothing, only try to authenticate.

=item -F

Do not save the commands typed in the interactive mode in the history file. 

=item -f <history>

Use the specified file to save command history.

=item -S <service>

This option sets the service name for SASL authentication. Default is "arc". This option has to be change on the server as well.

=item -u

Ask for username and use it for authentication.

=item -U <username>

lib/arcx.pod  view on Meta::CPAN

=item -W <password>

Use the <password> for authentication. (Only if an appropriate mechanism is used. (eg. PLAIN)).

=item -s <mechanism>

For authentication use the given <mechanism>. (Default: let the server decide.)

=item -t <timeout>

Timeout in seconds to wait for data in control and command connection.

=item -r <string>

<string> is going to be written to the established command connection, when command is used. (Do not wait for user input on STDIN).

eg.: arcx -r "data" test 
results in "at".

=item command

Run this ARCv2 command. Run "help" to see, which commands are available.

=item command-arguments

Some ARCv2 command can handle arguments. They should go here.

=back

=head1 SEE ALSO

L<Arc>, L<Arc::Command>, L<Arc::Connection>, 
L<Arc::Connection::Server>, L<Arc::Connection::Client>,
L<arcx>, L<arcxd>, L<Authen::SASL>, L<Authen::SASL::Cyrus>
L<Net::Server::PreFork>

lib/arcxd.pod  view on Meta::CPAN

=head1 NAME

arcxd - standalone ARCv2 server 

=head1 DESCRIPTION

This file is the scripts, which can be used, to start the ARCv2 server from the command line.

=head1 SYNOPSIS

This are some examples how to run the ARCv2 server.

=over 4

=item arcxd

Start the ARCv2 server. The server will listen on the DefaultPort and all local addresses.

lib/arcxd.pod  view on Meta::CPAN

   max_spare_servers = 10
   min_spare_servers = 2

   pid_file = /var/run/arcxd.pid
   
   sasl_mechanisms = <<EOM
 GSSAPI
 PLAIN
 EOM

 [commands]
   uptime = Arc::Command::Uptime
   whoami = Arc::Command::Whoami
   copy = Arc::Command::Get
   cp = Arc::Command::Get
   get = Arc::Command::Get
   put = Arc::Command::Put
   test = Arc::Command::Test
   help = Arc::Command::Help
   h = Arc::Command::Help
   hlp = Arc::Command::Help

lib/arcxd.pod  view on Meta::CPAN

=head2 main

=over 4

=item service

The name of the service the SASL authentication mechanism shall use.

=item timeout

Timeout in seconds to wait for data in control and command connection.

=back

=head2 arcd

=over 4

=item host

Here you can specify the address the server shall wait for connections. 0 lets the server listen on all interface on the host. 

lib/arcxd.pod  view on Meta::CPAN


These variables define the preforking behaviour. See L<Net::Server::PreFork> 
for more detailed descriptions.

=item sasl_mechanisms

A list of the possible SASL mechanisms, the server can supply to the clients. Can be filled by using the multi-line-string method known from perl.

=back

=head2 commands

=over 4

=item B<Command Name> = B<Command Class>

The section [commands] defines the assignments of command names to their command class. Each line is a command in ARCv2. A class can be assigned to more than one name.

=back

=head2 logging

=over 4

=item loglevel

This option specifies the login level of ARCv2. Default is 5, whereas 7 is the highest (DEBUG) and 1 is the lowest.

scripts/arcx  view on Meta::CPAN

$args{f} = defined $args{f} && $args{f} ne "" ? $args{f} : $ENV{HOME}.'/.archistory';
$args{C} = defined $args{C} && $args{C} ne "" ? $args{C} : $Arc::ConfigPath.'/arcx.conf';

my $intact = !@ARGV;
my $stop = 0;

my @server_list;

if ($args{h}) {
	push @server_list, $args{h}.($args{p} ? ":".$args{p} : "");
# only use the cmd2server maplist, when we have a command given
} elsif (!$intact && $args{C}) {
	unless (-e $args{C}) {
		err("Configfile $args{C} not found.");
	} else {
		my $cf = new Config::IniFiles( -file => $args{C});
		my $err = @Config::IniFiles::errors;
		usage($err) if $err;

		foreach ($cf->Parameters('server_command_map')) {
			my ($host,$cmdlist) = ($_,$cf->val('server_command_map',$_));
			push @server_list, $host
				if $cmdlist eq '*' || grep( { $_ eq $ARGV[0] } split(/[,:;]/, $cmdlist));
		}
	}
}

push @server_list, "$Arc::DefaultHost:$Arc::DefaultPort" unless @server_list;

my $retval = 0;

scripts/arcx  view on Meta::CPAN

	}
	verbout("Available SASL mechanisms return by the server: ",join(", ",@{$arc->{server_sasl_mechanisms}}));
	last;
}

exit $retval;

sub showhelp
{
	print <<EOT;
internal command for this client:
  ?      for this help
  \\q,^D  quit
EOT
}

sub usage
{
	my $msg = shift;
	print STDERR <<EOT;
$msg
$0 [-h <hostname>] [-p <port>] [-l <loglevel]
   [-L <logdestination] [-n] [-v] [-S <service>]
   [-F -f <history>] [-u|-U <username>] [-a|-A <authname>]
   [-w|-W <password>] [-s <mech>] [-t <timeout in sec>]
   [-r <string>] [-V] [-C <conffile>] [command [command-arguments]]

  (Remark: Some parameters behave different in comparison to the old arc)

  -h <hostname>    specify the ARCv2 server
  -p <port>        port to connect (default: $Arc::DefaultPort)
  -t <timeout>     specify the timeout in seconds (default: 30 secs)
  -0               use old protocol type (unencrypted protocol conn.)
  -C <conffile>    use <conffile> as source for server-command-mapping.
                   (default: $Arc::ConfigPath/arcx.conf)

  -r <string>      use this string as stdin value for the command

  -S <service>     name of the service used for arc auth (default: arc)
  -s <mech>        use <mech> as authentication mechanism for SASL
  -n               do nothing, just try to authenticate
  -v               be verbose

  -U <username>    username for authentication (dep. on SASL mechanism)
  -u               ask for username
  -A <authz name>  username for authorization (dep. SASL mechanism)
  -a               ask for authname
  -W <password>    password (dep. on SASL mechanism)
  -w               ask for password

  -f <history>     filename for command history (def: $ENV{HOME}/.archistory)
  -F               don't add commands to the history file

  -l <loglevel>    loglevel (see man Arc) (default: 0, error msgs will be on stderr)
  -L <logdest>     log destination (possible values: 'syslog' (def) or 'stderr')
  -V               display version information

$Arc::Copyright
$Arc::Contact
EOT

	exit 1;

scripts/arcx.conf  view on Meta::CPAN

# a very simple config file, which lists servers and their ARCv2 commands

[server_command_map]
    hekate.ifh.de:4243 = kstart,fs;vos:blah
    hekate.ifh.de:4242 = fs;vos:blah
    hekate2.ifh.de     = whoami,test,
# fallback
    hekate.ifh.de      = *

scripts/arcxd  view on Meta::CPAN

$prop->{min_spare_servers} = $cf->val("arcd","min_spare_servers");
$prop->{pid_file} = $args{P} ? $args{P} : $cf->val("arcd","pid_file",$Arc::DefaultPIDFile);
$prop->{background} = $args{d} ? undef : 1;

unless (open(FH,">".$prop->{pid_file})) {
	die "will not be able to create PID file ".$prop->{pid_file};
}
close(FH);

my $cmds = {};
foreach ($cf->Parameters("commands")) {
	$cmds->{$_} = $cf->val("commands",$_);
	verbout("adding possible command:",$_);
}

verbout("Available SASL mechanisms:",join(",",$cf->val("arcd","sasl_mechanisms")));
verbout("Loglevel:",$log{loglevel});
verbout("Logdest:",$log{logdestination});
verbout("Listenport:",join(",",@{$prop->{port}}));
verbout("Forking into background.") unless $args{d};
verbout("Using $Arc::Copyright.");
verbout("Contact: $Arc::Contact.");
verbout("Service: ",$cf->val("main","service"));
verbout("PID-file: ",$prop->{pid_file});

my $arc = new Arc::Server(
	%def,
	%log,

	connection_vars => {
		%log,
		timeout => $cf->val("main","timeout"),
		sasl_mechanisms => [$cf->val("arcd","sasl_mechanisms")],
		commands => $cmds,
		service => $cf->val("main","service"),
	}

);

if (my $msg = $arc->IsError()) {
	err($msg);
	exit 1;
}

scripts/arcxd.conf  view on Meta::CPAN

	max_spare_servers = 2

	pid_file = /var/state/arcxd.pid

	sasl_mechanisms = <<EOM
GSSAPI
KERBEROS_V4
ANONYMOUS
EOM
	
[commands]
	uptime = Arc::Command::Uptime
	whoami = Arc::Command::Whoami
	copy = Arc::Command::Get
	cp = Arc::Command::Get
	get = Arc::Command::Get
	put = Arc::Command::Put
	crontab = Arc::Command::Acrontab
	acrontab = Arc::Command::Acrontab
	test = Arc::Command::Test
	help = Arc::Command::Help

scripts/arcxd.init.d.solaris  view on Meta::CPAN

#!/bin/sh
# last mod 05.05.04 WN
#
# Need the commands ps, awk, kill, sleep
PATH=${PATH}${PATH:+:}/sbin:/bin:/usr/bin
 

killproc() {            # kill the named process(es)
        for x in `ps -e |grep " $@" |sed -e 's/^  *//' -e 's/ .*//'`
	do
                echo "PID: $x"
                [ ! -z "$pid" ] && echo killing $x && kill $pid &
        done
}

t/arc1.t  view on Meta::CPAN

					port => [30001], # Testport
					host => "localhost", 
				},
				connection_vars => {
					loglevel => 0,
					logdestination => 'stderr',
					sasl_mechanisms => ['PLAIN'],
					sasl_cb_checkpass => \&checkpass,
					sasl_cb_getsecret => \&getsecret,
					service => "arc",
					commands => { 
						test => 'Arc::Command::Test',
						whoami => 'Arc::Command::Whoami',
						uptime => 'Arc::Command::Uptime',
					}
				}
	);

	$server->Start();

	exit 0;



( run in 1.983 second using v1.01-cache-2.11-cpan-f56aa216473 )