view release on metacpan or search on metacpan
or libkopenafs library was found.
Mark autodie required for configure and use for correct automated
testing behavior on Perl 5.10.0. (autodie was added to core in
5.10.1.)
AFS::PAG 1.00 (2013-09-12)
Initial public release with support for libkafs, libkopenafs, and
Linux systems with no support library. pioctl is not yet supported,
only hasafs, haspag, setpag, and unlog. The build system has only
been tested on Debian.
Written by Russ Allbery <rra@cpan.org>
Copyright 2013, 2014 The Board of Trustees of the Leland Stanford Junior
University. This software is distributed under a BSD-style license.
Please see the section LICENSE below for more information.
BLURB
AFS::PAG provides the standard PAG and token manipulation functions
setpag and unlog to Perl programs as a native module. It also provides
the hasafs and haspag functions to detect whether AFS is running and
whether the current process is in a PAG. Unlike the more general AFS
module, it will build with any recent OpenAFS, Heimdal's libkafs, or on
Linux without any AFS libraries at all.
DESCRIPTION
AFS is a distributed file system allowing cross-platform sharing of
files among multiple computers. It associates client credentials
(called AFS tokens) with a Process Authentication Group, or PAG.
Test::Pod
Test::Pod::Coverage
Test::Spelling
Test::Strict
Test::Synopsis
All are available on CPAN. Those tests will be skipped if the modules
are not available.
To enable tests that may be sensitive to the local environment or that
produce a lot of false positives without uncovering many problems, set
RRA_MAINTAINER_TESTS to a true value.
BUILDING AND INSTALLATION
AFS::PAG uses Module::Build and can be installed using the same process
as any other Module::Build module:
perl Build.PL
./Build
./Build test
* Add config.guess and support the libkafs replacement for the other
operating systems on which it works. (Mac OS X, Solaris, and other
system-call-only platforms.)
* Add the necessary probes to link with OpenAFS libraries on AIX and
IRIX.
* Contribute back support for check_func to Config::AutoConf to clean up
the code in Build.PL.
* Honor all of the build settings passed to Module::Build when doing
probes with Config::AutoConf. This will probably require pulling the
ExtUtils::CBuilder object from Module::Build and modifying
Config::AutoConf to use the same builder.
kafs/kafs.c view on Meta::CPAN
/*
* kafs replacement, main API.
*
* This is a simple implementation of the k_hasafs, k_setpag, and k_unlog
* functions. It is for use on systems that don't have libkafs or
* libkopenafs, or where a dependency on those libraries is not desirable for
* some reason.
*
* A more robust implementation of the full kafs interface would have a
* separate header file with the various system call constants and would
* support more operations and the k_pioctl interface. Since this is a
* stripped-down implementation with only the few functions to do PAG
* management, various interface constants and system call numbers are
* hard-coded here.
kafs/kafs.c view on Meta::CPAN
#elif defined(HAVE_KAFS_SOLARIS)
# include <kafs/sys-solaris.c>
#elif defined(HAVE_KAFS_SYSCALL)
# include <kafs/sys-syscall.c>
#else
# error "Unknown AFS system call implementation"
#endif
/*
* On some platforms, k_hasafs needs to try a system call. This attempt may
* fail with SIGSYS. We therefore set a signal handler that changes a static
* variable if SIGSYS is received.
*
* It's really ugly to do this in library or PAM module in so many ways.
* Static variables are evil, changing signal handlers out from under an
* application is evil, and the interaction of signals and threads is probably
* nasty. The only things that make this better is that this case will never
* be triggered in the normal case of AFS being loaded and the only time that
* we change this static variable is to say that the call failed, so there
* shouldn't be a collision of updates from multiple calls.
*
kafs/kafs.c view on Meta::CPAN
rval = k_syscall(20, (long) path, cmd, (long) cmarg, follow, &err);
if (rval != 0)
err = rval;
return err;
}
/*
* Probe to see if AFS is available and we can make system calls successfully.
* This just attempts the set token system call with an empty token structure,
* which will be a no-op in the kernel.
*/
int
k_hasafs(void)
{
struct ViceIoctl iob;
int rval, saved_errno, okay;
void (*saved_func)(int);
saved_errno = errno;
kafs/kafs.c view on Meta::CPAN
signal(SIGSYS, saved_func);
#endif
okay = (syscall_okay && rval == -1 && errno == EINVAL);
errno = saved_errno;
return okay;
}
/*
* The setpag system call. This is special in that it's not a pioctl;
* instead, it's a separate system call done directly through the afs_syscall
* function.
*/
int
k_setpag(void)
{
int err, rval;
rval = k_syscall(21, 0, 0, 0, 0, &err);
if (rval != 0)
err = rval;
return err;
}
kafs/sys-darwin10.c view on Meta::CPAN
unsigned int syscall;
unsigned int retval;
};
/*
* The workhorse function that does the actual system call. All the values
* are passed as longs to match the internal OpenAFS interface, which means
* that there's all sorts of ugly type conversion happening here.
*
* Returns -1 and sets errno to ENOSYS if attempting a system call fails and 0
* otherwise. If the system call was made, its return status will be stored
* in rval.
*/
static int
k_syscall(long call, long param1, long param2, long param3, long param4,
int *rval)
{
int fd, code, oerrno;
fd = open("/dev/openafs_ioctl", O_RDWR);
kafs/sys-darwin8.c view on Meta::CPAN
unsigned int param6;
unsigned int retval;
};
/*
* The workhorse function that does the actual system call. All the values
* are passed as longs to match the internal OpenAFS interface, which means
* that there's all sorts of ugly type conversion happening here.
*
* Returns -1 and sets errno to ENOSYS if attempting a system call fails and 0
* otherwise. If the system call was made, its return status will be stored
* in rval.
*/
static int
k_syscall(long call, long param1, long param2, long param3, long param4,
int *rval)
{
struct afssysargs syscall_data;
int fd, code, oerrno;
kafs/sys-linux.c view on Meta::CPAN
/*
* The workhorse function that does the actual system call. All the values
* are passed as longs to match the internal OpenAFS interface, which means
* that there's all sorts of ugly type conversion happening here.
*
* The first path we attempt is the OpenAFS path; the second is the one used
* by Arla (at least some versions).
*
* Returns -1 and sets errno to ENOSYS if attempting a system call fails and 0
* otherwise. If the system call was made, its return status will be stored
* in rval.
*/
static int
k_syscall(long call, long param1, long param2, long param3, long param4,
int *rval)
{
struct afsprocdata syscall_data;
int fd, oerrno;
kafs/sys-solaris.c view on Meta::CPAN
uint64_t param1;
uint32_t syscall;
};
/*
* The workhorse function that does the actual system call. All the values
* are passed as longs to match the internal OpenAFS interface, which means
* that there's all sorts of ugly type conversion happening here.
*
* Returns -1 and sets errno to ENOSYS if attempting a system call fails and 0
* otherwise. If the system call was made, its return status will be stored
* in rval.
*/
static int
k_syscall(long call, long param1, long param2, long param3, long param4,
int *rval)
{
int fd, code, oerrno, callnum;
#ifdef _ILP32
lib/AFS/PAG.pm view on Meta::CPAN
use warnings;
use base qw(DynaLoader);
use Exporter qw(import);
our (@EXPORT_OK, $VERSION);
# Set all import-related variables in a BEGIN block for robustness.
BEGIN {
@EXPORT_OK = qw(hasafs haspag setpag unlog);
$VERSION = '1.02';
}
# Load the binary module.
bootstrap AFS::PAG $VERSION;
1;
__END__
=for stopwords
Allbery AFS PAG libkafs libkopenafs Kerberos aklog UID kdestroy
=head1 NAME
AFS::PAG - Perl bindings for AFS PAG manipulation
=head1 SYNOPSIS
use AFS::PAG qw(hasafs setpag unlog);
if (hasafs()) {
setpag();
system('aklog') == 0
or die "cannot get tokens\n";
do_afs_things();
unlog();
}
=head1 DESCRIPTION
AFS is a distributed file system allowing cross-platform sharing of files
among multiple computers. It associates client credentials (called AFS
tokens) with a Process Authentication Group, or PAG. AFS::PAG makes
available in Perl the PAG manipulation functions provided by the libkafs
or libkopenafs libraries.
With the functions provided by this module, a Perl program can detect
whether AFS is available on the local system (hasafs()) and whether it is
currently running inside a PAG (haspag()). It can also create a new PAG
and put the current process in it (setpag()) and remove any AFS tokens in
the current PAG (unlog()).
Note that this module doesn't provide a direct way to obtain new AFS
tokens. Programs that need AFS tokens should normally obtain Kerberos
tickets (via whatever means) and then run the program B<aklog>, which
comes with most AFS distributions. This program will create AFS tokens
from the current Kerberos ticket cache and store them in the current PAG.
To isolate those credentials from the rest of the system, call setpag()
before running B<aklog>.
=head1 FUNCTIONS
This module provides the following functions, none of which are exported
by default:
=over 4
=item hasafs()
lib/AFS/PAG.pm view on Meta::CPAN
otherwise.
=item haspag()
Returns true if the current process is running inside a PAG and false
otherwise. AFS tokens obtained outside of a PAG are visible to any
process on the system outside of a PAG running as the same UID. AFS
tokens obtained inside a PAG are visible to any process in the same PAG,
regardless of UID.
=item setpag()
Creates a new, empty PAG and put the current process in it. This should
normally be called before obtaining new AFS tokens to isolate those tokens
from other processes on the system. Returns true on success and throws
an exception on failure.
=item unlog()
Deletes all AFS tokens in the current PAG, similar to the action of
B<kdestroy> on a Kerberos ticket cache. Returns true on success and
throws an exception on failure.
=back
=head1 DIAGNOSTICS
=over 4
=item PAG creation failed: %s
setpag() failed. The end of the error message will be a translation of
the system call error number.
=item Token deletion failed: %s
unlog() failed. The end of the error message will be a translation of
the system call error number.
=back
=head1 RESTRICTIONS
lib/AFS/PAG.xs view on Meta::CPAN
void
haspag()
PPCODE:
if (k_haspag())
XSRETURN_YES;
else
XSRETURN_UNDEF;
void
setpag()
PPCODE:
if (k_setpag() == 0)
XSRETURN_YES;
else
croak("PAG creation failed: %s", strerror(errno));
void
unlog()
PPCODE:
if (k_unlog() == 0)
XSRETURN_YES;
portable/kafs.h view on Meta::CPAN
/*
* Portability wrapper around the kafs API.
*
* This header includes kafs.h if it's available, prototypes k_hasafs,
* k_setpag, and k_unlog replacements (generally provided by the kafs
* replacement library) imlemented in terms of our system call layer or
* lsetpag if it is available and libkafs isn't, and as a last resort provides
* a k_hasafs function that always fails and k_setpag and k_unlog functions
* that always succeed.
*
* It also defines the HAVE_KAFS macro to 1 if some AFS support was available,
* in case programs that use it want to handle the case of no AFS support
* differently (such as in help output).
*
* The canonical version of this file is maintained in the rra-c-util package,
* which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
*
* Written by Russ Allbery <eagle@eyrie.org>
portable/kafs.h view on Meta::CPAN
# elif HAVE_KOPENAFS_H
# include <kopenafs.h>
# else
struct ViceIoctl {
void *in, *out;
short in_size;
short out_size;
};
int k_hasafs(void);
int k_pioctl(char *, struct ViceIoctl *, void *, int);
int k_setpag(void);
int k_unlog(void);
# endif
# ifdef HAVE_K_HASPAG
# if !defined(HAVE_KAFS_H) && !defined(HAVE_KOPENAFS_H)
int k_haspag(void);
# endif
# else
int k_haspag(void) __attribute__((__visibility__("hidden")));
# endif
/* We're linking directly to the OpenAFS libraries. */
#elif HAVE_LSETPAG
# if HAVE_AFS_AFSSYSCALLS_H
# include <afs/afssyscalls.h>
# else
int lsetpag(void);
int lpioctl(char *, int, void *, int);
# endif
# define k_hasafs() (1)
# define k_pioctl(p, c, a, f) lpioctl((p), (c), (a), (f))
# define k_setpag() lsetpag()
# define k_unlog() (errno = ENOSYS, -1)
int k_haspag(void) __attribute__((__visibility__("hidden")));
/* We're using our local kafs replacement. */
#elif HAVE_KAFS_REPLACEMENT
# define HAVE_K_PIOCTL 1
struct ViceIoctl {
void *in, *out;
short in_size;
short out_size;
};
/* Default to a hidden visibility for all portability functions. */
#pragma GCC visibility push(hidden)
int k_hasafs(void);
int k_haspag(void);
int k_pioctl(char *, int, struct ViceIoctl *, int);
int k_setpag(void);
int k_unlog(void);
/* Undo default visibility change. */
#pragma GCC visibility pop
/* We have no kafs implementation available. */
#else
# undef HAVE_KAFS
# define k_hasafs() (0)
# define k_haspag() (0)
# define k_pioctl(p, c, a, f) (errno = ENOSYS, -1)
# define k_setpag() (errno = ENOSYS, -1)
# define k_unlog() (errno = ENOSYS, -1)
#endif
END_DECLS
#endif /* PORTABLE_KAFS_H */
portable/macros.h view on Meta::CPAN
* variadic macro support.
*/
#if !defined(__attribute__) && !defined(__alloc_size__)
# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
# define __alloc_size__(spec, args...) /* empty */
# endif
#endif
/*
* LLVM and Clang pretend to be GCC but don't support all of the __attribute__
* settings that GCC does. For them, suppress warnings about unknown
* attributes on declarations. This unfortunately will affect the entire
* compilation context, but there's no push and pop available.
*/
#if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__))
# pragma GCC diagnostic ignored "-Wattributes"
#endif
/*
* BEGIN_DECLS is used at the beginning of declarations so that C++
* compilers don't mangle their names. END_DECLS is used at the end.
portable/system.h view on Meta::CPAN
#ifndef PORTABLE_SYSTEM_H
#define PORTABLE_SYSTEM_H 1
/* Make sure we have our configuration information. */
#include <config.h>
/* BEGIN_DECL and __attribute__. */
#include <portable/macros.h>
/* A set of standard ANSI C headers. We don't care about pre-ANSI systems. */
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdio.h>
t/data/perlcriticrc view on Meta::CPAN
[InputOutput::RequireBriefOpen]
lines = 25
# This is correct 80% of the time, but it isn't correct for a lot of scripts
# inside packages, where maintaining $VERSION isn't worth the effort.
# Unfortunately, there's no way to override it, so it gets turned off
# globally.
[-Modules::RequireVersionVar]
# This sounds interesting but is actually useless. Any large blocks of
# literal text, which does not add to the complexity of the regex, will set it
# off.
[-RegularExpressions::ProhibitComplexRegexes]
# I generally don't want to require Readonly as a prerequisite for all my Perl
# modules.
[-ValuesAndExpressions::ProhibitConstantPragma]
# A good idea, but there are too many places where this would be more
# confusing than helpful. Pull out numbers if one might change them
# independent of the algorithm, but don't do so for mathematical formulae.
t/lib/Test/RRA.pm view on Meta::CPAN
use 5.006;
use strict;
use warnings;
use Exporter;
use Test::More;
# For Perl 5.006 compatibility.
## no critic (ClassHierarchies::ProhibitExplicitISA)
# Declare variables that should be set in BEGIN for robustness.
our (@EXPORT_OK, @ISA, $VERSION);
# Set $VERSION and everything export-related in a BEGIN block for robustness
# against circular module loading (not that we load any modules, but
# consistency is good).
BEGIN {
@ISA = qw(Exporter);
@EXPORT_OK = qw(skip_unless_author skip_unless_automated use_prereq);
# This version should match the corresponding rra-c-util release, but with
t/lib/Test/RRA.pm view on Meta::CPAN
$error = $@;
$sigdie = $SIG{__DIE__} || undef;
}
# If the use failed for any reason, skip the test.
if (!$result || $error) {
my $name = length($version) > 0 ? "$module $version" : $module;
plan skip_all => "$name required for test";
}
# If the module set $SIG{__DIE__}, we cleared that via local. Restore it.
## no critic (Variables::RequireLocalizedPunctuationVars)
if (defined($sigdie)) {
$SIG{__DIE__} = $sigdie;
}
return;
}
1;
__END__
t/lib/Test/RRA.pm view on Meta::CPAN
=head1 FUNCTIONS
None of these functions are imported by default. The ones used by a
script should be explicitly imported.
=over 4
=item skip_unless_author(DESC)
Checks whether AUTHOR_TESTING is set in the environment and skips the
whole test (by calling C<plan skip_all> from Test::More) if it is not.
DESC is a description of the tests being skipped. A space and C<only run
for author> will be appended to it and used as the skip reason.
=item skip_unless_automated(DESC)
Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are
set in the environment and skips the whole test (by calling C<plan
skip_all> from Test::More) if they are not. This should be used by tests
that should not run during end-user installs of the module, but which
should run as part of CPAN smoke testing and release testing.
DESC is a description of the tests being skipped. A space and C<normally
skipped> will be appended to it and used as the skip reason.
=item use_prereq(MODULE[, VERSION][, IMPORT ...])
Attempts to load MODULE with the given VERSION and import arguments. If
t/lib/Test/RRA/Config.pm view on Meta::CPAN
# Configuration for Perl test cases.
#
# In order to reuse the same Perl test cases in multiple packages, I use a
# configuration file to store some package-specific data. This module loads
# that configuration and provides the namespace for the configuration
# settings.
#
# The canonical version of this file is maintained in the rra-c-util package,
# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
package Test::RRA::Config;
use 5.006;
use strict;
use warnings;
# For Perl 5.006 compatibility.
## no critic (ClassHierarchies::ProhibitExplicitISA)
use Exporter;
use Test::More;
# Declare variables that should be set in BEGIN for robustness.
our (@EXPORT_OK, @ISA, $VERSION);
# Set $VERSION and everything export-related in a BEGIN block for robustness
# against circular module loading (not that we load any modules, but
# consistency is good).
BEGIN {
@ISA = qw(Exporter);
@EXPORT_OK = qw(
$COVERAGE_LEVEL @COVERAGE_SKIP_TESTS @CRITIC_IGNORE $LIBRARY_PATH
$MINIMUM_VERSION %MINIMUM_VERSION @POD_COVERAGE_EXCLUDE @STRICT_IGNORE
@STRICT_PREREQ
);
# This version should match the corresponding rra-c-util release, but with
# two digits for the minor version, including a leading zero if necessary,
# so that it will sort properly.
$VERSION = '5.05';
}
# If BUILD or SOURCE are set in the environment, look for data/perl.conf under
# those paths for a C Automake package. Otherwise, look in t/data/perl.conf
# for a standalone Perl module. Don't use Test::RRA::Automake since it may
# not exist.
our $PATH;
for my $base ($ENV{BUILD}, $ENV{SOURCE}, 't') {
next if !defined($base);
my $path = "$base/data/perl.conf";
if (-r $path) {
$PATH = $path;
last;
}
}
if (!defined($PATH)) {
BAIL_OUT('cannot find data/perl.conf');
}
# Pre-declare all of our variables and set any defaults.
our $COVERAGE_LEVEL = 100;
our @COVERAGE_SKIP_TESTS;
our @CRITIC_IGNORE;
our $LIBRARY_PATH;
our $MINIMUM_VERSION = '5.008';
our %MINIMUM_VERSION;
our @POD_COVERAGE_EXCLUDE;
our @STRICT_IGNORE;
our @STRICT_PREREQ;
t/lib/Test/RRA/Config.pm view on Meta::CPAN
=head1 DESCRIPTION
Test::RRA::Config encapsulates per-package configuration for generic Perl
test programs that are shared between multiple packages using the
rra-c-util infrastructure. It handles locating and loading the test
configuration file for both C Automake packages and stand-alone Perl
modules.
Test::RRA::Config looks for a file named F<data/perl.conf> relative to the
root of the test directory. That root is taken from the environment
variables BUILD or SOURCE (in that order) if set, which will be the case
for C Automake packages using C TAP Harness. If neither is set, it
expects the root of the test directory to be a directory named F<t>
relative to the current directory, which will be the case for stand-alone
Perl modules.
The following variables are supported:
=over 4
=item $COVERAGE_LEVEL
t/lib/Test/RRA/Config.pm view on Meta::CPAN
testing using Test::Strict, as a percentage. The test will fail if test
coverage less than this percentage is achieved. If not given, defaults
to 100.
=item @COVERAGE_SKIP_TESTS
Directories under F<t> whose tests should be skipped when doing coverage
testing. This can be tests that won't contribute to coverage or tests
that don't run properly under Devel::Cover for some reason (such as ones
that use taint checking). F<docs> and F<style> will always be skipped
regardless of this setting.
=item @CRITIC_IGNORE
Additional directories to ignore when doing recursive perlcritic testing.
The contents of this directory must be either top-level directory names or
directory names starting with F<tests/>.
=item $LIBRARY_PATH
Add this directory (or a F<.libs> subdirectory) relative to the top of the
t/pag/basic.t view on Meta::CPAN
use lib 't/lib';
use Test::RRA qw(use_prereq);
BEGIN { use_prereq('IPC::System::Simple', qw(capturex systemx)) }
# Establish the plan now that we know we're continuing.
use Test::More tests => 6;
# Load the module.
BEGIN { use_ok('AFS::PAG', qw(hasafs haspag setpag unlog)) }
# Determines if the user has valid tokens by running tokens.
#
# Returns: True if the user has valid tokens, false if not or if tokens fails
sub has_tokens {
my $tokens = eval { capturex('tokens') };
if (!$@ && $tokens =~ m{ [ ] tokens [ ] for [ ] }xmsi) {
return 1;
} else {
return;
t/pag/basic.t view on Meta::CPAN
}
# If k_hasafs returns false, we can't run any other tests.
SKIP: {
if (!hasafs()) {
skip 'AFS not available', 5;
}
# See if we already have tokens. If so, we can do some other tests.
my $had_tokens = has_tokens();
ok(setpag(), 'k_setpag succeeds');
ok(haspag(), '...and we are now in a PAG');
# If we had tokens, check to see if k_setpag hides them.
SKIP: {
if (!$had_tokens) {
skip 'cannot check token hiding without existing tokens', 1;
}
ok(!has_tokens(), '...and hides existing tokens');
}
# Try to obtain tokens with aklog and test unlog.
my $status = eval { systemx('aklog') };
SKIP: {
t/pag/isolation.t view on Meta::CPAN
use lib 't/lib';
use Test::RRA qw(use_prereq);
BEGIN { use_prereq('IPC::System::Simple', qw(capturex systemx)) }
# Establish the plan now that we know we're continuing.
use Test::More tests => 3;
# Load the module.
BEGIN { use_ok('AFS::PAG', qw(hasafs setpag unlog)) }
# Determines if the user has valid tokens by running tokens.
#
# Returns: True if the user has valid tokens, false if not or if tokens fails
sub has_tokens {
my $tokens = eval { capturex('tokens') };
if (!$@ && $tokens =~ m{ [ ] tokens [ ] for [ ] }xmsi) {
return 1;
} else {
return;
t/pag/isolation.t view on Meta::CPAN
# We need AFS support and existing tokens to run this test.
SKIP: {
if (!hasafs() || !has_tokens()) {
skip 'AFS tokens not available', 2;
}
# Fork off a child that creates a new PAG and then runs unlog. This
# should not affect the tokens in our parent process.
my $pid = fork;
if ($pid == 0) {
setpag();
unlog();
exit(0);
} else {
waitpid($pid, 0);
}
# Check that the child calls succeeded.
is($?, 0, 'Child setpag and unlog succeeded');
# Check that we still have tokens.
ok(has_tokens(), 'Parent process still has tokens');
}