CipUX-Storage-3.4.0.2/0000755000175000017500000000000011237647212014451 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/doc/0000755000175000017500000000000011237647212015216 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/doc/debian-edu/0000755000175000017500000000000011237647212017213 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/doc/debian-edu/task.ldif0000444000175000017500000000014311237647212021011 0ustar ckuelkerckuelkerdn: ou=Task,dc=skole,dc=skolelinux,dc=no objectClass: top objectClass: organizationalUnit ou: Task CipUX-Storage-3.4.0.2/doc/debian-edu/cipuxroot.ldif0000444000175000017500000000031011237647212022077 0ustar ckuelkerckuelkerdn: cn=cipuxroot,dc=skole,dc=skolelinux,dc=no objectClass: simpleSecurityObject objectClass: organizationalRole cn: cipuxroot description: CipUX master account (not for admin use!) userPassword: @PW@ CipUX-Storage-3.4.0.2/doc/debian-edu/slapd_acl_cipuxroot.conf0000444000175000017500000000323711237647212024123 0ustar ckuelkerckuelker# CipUX authenticates with LDAP using the account cipuxroot. # This account needs access to objects CipUX supports. # ...but should be excluded from other access for improved security. # Allow authentication and updating itself access to dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 =wx by * none break # Allow overwriting passwords but not reading or guessing access to attrs=userPassword,sambaLMPassword,sambaNTPassword by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 =w by * none break access to dn.subtree="ou=Group,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break access to dn.subtree="ou=People,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break access to dn.subtree="ou=Netgroup,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break access to dn.subtree="ou=CAT,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break access to dn.subtree="ou=Room,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break access to dn.subtree="ou=Task,dc=skole,dc=skolelinux,dc=no" by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write by * none break # Not yet supported by CipUX #access to dn.exact="cn=nextID,ou=Variables,dc=skole,dc=skolelinux,dc=no" # attrs=gidNumber # by dn.exact="cn=cipuxroot,dc=skole,dc=skolelinux,dc=no" ssf=128 write # by * none break CipUX-Storage-3.4.0.2/doc/debian-edu/cipadmin-user.ldif0000444000175000017500000000120511237647212022607 0ustar ckuelkerckuelkerdn: uid=cipadmin,ou=People,dc=skole,dc=skolelinux,dc=no objectClass: top objectClass: posixAccount objectClass: shadowAccount objectClass: imapUser objectClass: cipuxAccount cipuxCreationDate: 2008-08-10T21:56:40 cipuxFirstname: CipUX cipuxHardQuota: 200000 cipuxInternetStatus: accept cipuxIsAccount: TRUE cipuxLastname: Admin cipuxRemark: CipUX task layer cipuxRole: admin cipuxSkeletonUid: none cipuxSoftQuota: 100000 cipuxStatus: idle cn: CipUX Admin gecos: CipUX Admin gidNumber: 10001 homeDirectory: /home/cipux0/cipadmin loginShell: /bin/bash mailMessageStore: /var/lib/maildirs/cipadmin uid: cipadmin uidNumber: 10001 userPassword: @PW@ CipUX-Storage-3.4.0.2/doc/debian-edu/extrastructs.patch0000444000175000017500000000637511237647212023020 0ustar ckuelkerckuelker--- a/etc/cipux/cipux-storage-structure.conf 2009-02-11 11:09:54.000000000 +0100 +++ b/etc/cipux/cipux-storage-structure.conf 2009-02-11 10:45:37.000000000 +0100 @@ -54,7 +54,7 @@ }, 'cipux_client' => { desc => 'access all CipUX client nodes', - struc_rdn => 'ou=Machine', + struc_rdn => 'ou=Machines,ou=People', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxMachine)', }, @@ -84,7 +84,7 @@ }, 'cipux_account.user' => { desc => 'access all CipUX user account user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsAccount=TRUE)', @@ -103,7 +103,7 @@ }, 'cipux_guest_account.user' => { desc => 'access all CipUX user guest_account user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsGuestAccount=TRUE)', @@ -117,7 +117,7 @@ }, 'cipux_examinee_account.user' => { desc => 'access all CipUX user examinee_account user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsExamineeAccount=TRUE)', @@ -131,7 +131,7 @@ }, 'cipux_share.user' => { desc => 'access all CipUX user share user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsShare=TRUE)', }, @@ -143,7 +143,7 @@ }, 'cipux_global_share.user' => { desc => 'access all CipUX user global_share user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsGlobalShare=TRUE)', @@ -157,7 +157,7 @@ }, 'cipux_examination_share.user' => { desc => 'access all CipUX user examination_share user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsExaminationShare=TRUE)', @@ -171,7 +171,7 @@ }, 'cipux_documenation_share.user' => { desc => 'access all CipUX user documenation_share user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsDocumentationShare=TRUE)', @@ -185,7 +185,7 @@ }, 'cipux_skel.user' => { desc => 'access all CipUX user skel user nodes', - struc_rdn => 'ou=User', + struc_rdn => 'ou=People', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsSkel=TRUE)', }, CipUX-Storage-3.4.0.2/doc/debian-edu/room.ldif0000444000175000017500000000014311237647212021023 0ustar ckuelkerckuelkerdn: ou=Room,dc=skole,dc=skolelinux,dc=no objectClass: top objectClass: organizationalUnit ou: Room CipUX-Storage-3.4.0.2/doc/debian-edu/cipadmin-group.ldif0000444000175000017500000000057411237647212022775 0ustar ckuelkerckuelkerdn: cn=cipadmin,ou=Group,dc=skole,dc=skolelinux,dc=no objectClass: top objectClass: posixGroup objectClass: cipuxGroup cipuxCreationDate: 2008-08-10T21:56:40 cipuxGroupLeaderUid: cipadmin cipuxHardQuota: 400000 cipuxInternetStatus: accept cipuxIsAccount: TRUE cipuxRemark: CipUX task layer cipuxRole: admin cipuxSoftQuota: 300000 cn: cipadmin gidNumber: 10001 memberUid: cipadmin CipUX-Storage-3.4.0.2/doc/debian-edu/cat.ldif0000444000175000017500000000014111237647212020614 0ustar ckuelkerckuelkerdn: ou=CAT,dc=skole,dc=skolelinux,dc=no objectClass: top objectClass: organizationalUnit ou: CAT CipUX-Storage-3.4.0.2/lib/0000755000175000017500000000000011237647212015217 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/lib/CipUX/0000755000175000017500000000000011237647212016207 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/lib/CipUX/Storage/0000755000175000017500000000000011237647212017613 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/lib/CipUX/Storage/Client.pm0000444000175000017500000011302411237647212021366 0ustar ckuelkerckuelker# +==========================================================================+ # || CipUX::Storage::Client || # || || # || CipUX storage abstraction layer || # || || # || Copyright (C) 2008 - 2009 by Christian Kuelker. All rights reserved! || # || || # || License: GNU GPL version 2 or any later version. || # || || # +==========================================================================+ # ID: $Id$ # Revision: $Revision$ # Head URL: $HeadURL$ # Date: $Date$ # Source: $Source$ package CipUX::Storage::Client; use 5.008001; use strict; use warnings; use Carp; use Class::Std; use Data::Dumper; use English qw( -no_match_vars); use Getopt::Long; use Log::Log4perl qw(:easy); use Pod::Usage; use Readonly; use base qw(CipUX CipUX::Storage); { # BEGIN CLASS use version; our $VERSION = qv('3.4.0.2'); use re 'taint'; # Keep tainted any data captured by parens delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; # Make %ENV safe # +======================================================================+ # || CONST || # +======================================================================+ Readonly::Scalar my $EMPTY_STRING => q{}; Readonly::Scalar my $LINEWIDTH => 78; Readonly::Scalar my $L4PCONF => '/etc/cipux/log4perl.conf'; Readonly::Array my @ACTION => qw( get_all_values set_all_values add_node get_value set_value list delete_node rename_node ); # +======================================================================+ # || INIT ARGS || # +======================================================================+ # register client with name: # name : cipux_storage_client my %name_of : ATTR( init_arg => 'name'); # +======================================================================+ # || GLOBAL || # +======================================================================+ my $L = q{=} x $LINEWIDTH; $L .= "\n"; my $maxcol_ar = []; my $value_ar = []; my $attrvalue_hr = {}; my $mattrvalue_hr = {}; my %opt = (); my %option = ( 'cipux_storage_client' => { 'must' => [qw(t=storage_task l=list)], 'may' => [qw(c cfg h ? help D debug p pretty V verbose version )], 'not' => [qw(a add c d e r t v x y)], }, 'add_node' => { 'must' => [qw(t=storage_task x=mattrvalue s=type o=object)], 'may' => [qw(c cfg h ? help D debug V verbose version )], 'not' => [ qw(a add d delete e erase p prettey r replace v value y attrvalue) ], }, 'delete_node' => { 'must' => [qw(t=storage_task s=type o=object)], 'may' => [qw(c cfg h ? help D debug V verbose version )], 'not' => [ qw(a add d delete e erase p prettey r replace v value x mattrvalue y attrvalue) ], }, 'rename_node' => { 'must' => [qw(t=storage_task s=type o=object v=value)], 'may' => [qw(c cfg h ? help D debug V verbose version )], 'not' => [ qw(a add d delete e erase p prettey r replace y attrvalue x mattrvalue) ], }, 'get_value' => { 'must' => [qw(t=storage_task y=attrvalue s=type o=object)], 'may' => [qw(c cfg h ? help D debug pretty V verbose version )], 'not' => [qw(a add d delete e erase r replace v value x mattrvalue)], }, 'get_all_values' => { 'must' => [qw(t=storage_task y=attrvalue s=type)], 'may' => [qw(c cfg h ? help D debug p pretty V verbose version )], 'not' => [ qw(a add d delete e erase o object r replace v value x mattrvalue) ], }, 'set_value' => { 'must' => [qw(t=storage_task y=attrvalue s=type o=object)], 'may' => [ qw(a add d delete c cfg e erase h ? help D debug r replace v value V verbose version ) ], 'not' => [qw(p prettey x mattrvalue)], }, 'set_all_values' => { 'must' => [qw(t=storage_task y=attrvalue s=type)], 'may' => [ qw(a add d delete c cfg erase h ? help D debug r replace v value V verbose version ) ], 'not' => [qw(o object p prettey x mattrvalue)], }, ); # +======================================================================+ # || run || # +======================================================================+ sub run { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; # constructor parameter from CipUX::Storage::Client my $script = $name_of{ ident $self}; # test right away if we have a valid name if ( $script ne 'cipux_storage_client' ) { $self->exc( { msg => 'unknown script name', value => $script } ); } # +------------------------------------------------------------------+ # | Environment Getopt::Long::Configure('bundling'); my $store_attrvalue = sub { $self->store_attrvalue( $attrvalue_hr, @_ ) }; my $store_mattrvalue = sub { $self->store_mattrvalue( $mattrvalue_hr, @_ ) }; GetOptions( \%opt, 'add|a', 'cfg|c=s', 'debug|D', 'delete|d', 'erase|e', 'help|h', 'list|l', 'gum|g=i', 'object|o=s', 'pretty|p', 'replace|r', 'type|s=s', 'storage_task|t=s', 'value|v=s', 'version|V', 'verbose', 'mattrvalue|x=s%' => sub { $self->store_mattrvalue( $mattrvalue_hr, \%opt, @_ ); }, 'attrvalue|y:s%' => sub { $self->store_attrvalue( $attrvalue_hr, \%opt, @_ ); }, ) or pod2usage( -exitstatus => 2, -msg => "$L problems parsing command line!\n$L" ); if ( defined $opt{debug} ) { Log::Log4perl->init_once($L4PCONF); } my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'opt: ', { filter => \&Dumper, value => \%opt } ); $logger->debug( 'attrvalue_hr: ', { filter => \&Dumper, value => $attrvalue_hr } ); $logger->debug( 'mattrvalue_hr: ', { filter => \&Dumper, value => $mattrvalue_hr } ); # display help page if ( exists $opt{help} ) { pod2usage( -exitstatus => 0, -verbose => 1 ); } my $storage_task = exists $opt{storage_task} ? $opt{storage_task} : undef; if ( not defined $storage_task ) { my $msg = "$L Please give parameter --storage_task or -t! \n"; $msg .= "valid storage tasks are: \n"; foreach my $a (@ACTION) { $msg .= "$a\n"; } $msg .= $L; pod2usage( -exitstatus => 1, -verbose => 0, -msg => $msg ); } $logger->debug( 'storage_task: ', $storage_task ); if ( exists $opt{version} ) { $self->out("$script $VERSION\n"); exit 0; } my $ret = $self->test_cli_option( { script => $storage_task, logic_hr => \%option, opt_hr => \%opt, } ); # +------------------------------------------------------------------+ # | main my $cfg = exists $opt{cfg} ? $opt{cfg} : undef; if ( defined $cfg ) { $logger->debug( 'cfg: ', $cfg ); } my $escope = exists $opt{erase} ? 'all' : 'one'; my $changes = exists $opt{erase} ? 'delete' : exists $opt{delete} ? 'delete' : exists $opt{add} ? 'add' : exists $opt{replace} ? 'replace' : 'replace'; my $scope = $storage_task eq 'get_value' ? 'one' : $storage_task eq 'set_value' ? 'one' : $storage_task eq 'get_all_values' ? 'all' : $storage_task eq 'set_all_values' ? 'all' : 'one'; my $pretty = exists $opt{pretty} ? 1 : 0; my $object = exists $opt{object} ? $opt{object} : $EMPTY_STRING; # s = type my $type = exists $opt{type} ? $opt{type} : $EMPTY_STRING; my $value = exists $opt{value} ? $opt{value} : $EMPTY_STRING; my $configfile = exists $opt{cfg} ? $opt{cfg} : $EMPTY_STRING; if ( scalar( grep { $_ eq $storage_task } @ACTION ) < 1 ) { my $msg = "unknown storage task [$storage_task]\n"; $msg .= "valid storage tasks are: \n"; foreach my $a (@ACTION) { $msg .= "$a\n"; } $msg .= $L; $self->exc( { msg => $msg } ); } my $sub = 'cipux_storage_' . $storage_task; $self->$sub( { scope => $scope, escope => $escope, pretty => $pretty, type => $type, object => $object, value => $value, cfg => $cfg, } ); return; } # +----------------------------------------------------------------------+ # | cipux_storage_list | # +----------------------------------------------------------------------+ sub cipux_storage_list { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $pretty = exists $arg_r->{pretty} ? $self->l( $arg_r->{pretty} ) : $self->perr('pretty'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'pretty: ', $pretty ); $logger->debug( 'cfg: ', { filter => \&Dumper, value => $cfg } ); $self->_print_list_type( { pretty => $pretty, cfg => $cfg } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_get_value | # +----------------------------------------------------------------------+ sub cipux_storage_get_value { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); my $pretty = exists $arg_r->{pretty} ? $self->l( $arg_r->{pretty} ) : $self->perr('pretty'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'attrvalue_hr: ', { filter => \&Dumper, value => $attrvalue_hr } ); #$attrvalue_hr->{cipuxAddress} = 'cipuxAddress'; my $storage = CipUX::Storage->new(); my $value_hr = $storage->get_value( { scope => $scope, type => $type, obj => $object, attr_ar => [ %{$attrvalue_hr} ], } ); $self->_print_values( { scope => $scope, pretty => $pretty, value_hr => $value_hr } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_get_all_values | # +----------------------------------------------------------------------+ sub cipux_storage_get_all_values { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); my $pretty = exists $arg_r->{pretty} ? $self->l( $arg_r->{pretty} ) : $self->perr('pretty'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $value_hr = $storage->get_value( { scope => $scope, type => $type, obj => $object, attr_ar => [ %{$attrvalue_hr} ] } ); $self->_print_values( { scope => $scope, pretty => $pretty, value_hr => $value_hr } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_set_value | # +----------------------------------------------------------------------+ sub cipux_storage_set_value { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); my $escope = exists $arg_r->{escope} ? $self->l( $arg_r->{escope} ) : $self->perr('escope'); my $changes = exists $arg_r->{changes} ? $self->l( $arg_r->{changes} ) : $self->perr('changes'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); my $value = exists $arg_r->{value} ? $self->l( $arg_r->{value} ) : $self->perr('value'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $value_hr = $storage->set_value( { scope => $scope, # scope referencing objects escope => $escope, # scope referencing attributes (e=erase) changes => $changes, type => $type, obj => $object, value => $value, attr_ar => [ %{$attrvalue_hr} ] } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_set_all_values | # +----------------------------------------------------------------------+ sub cipux_storage_set_all_values { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); my $escope = exists $arg_r->{escope} ? $self->l( $arg_r->{escope} ) : $self->perr('escope'); my $changes = exists $arg_r->{changes} ? $self->l( $arg_r->{changes} ) : $self->perr('changes'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); my $value = exists $arg_r->{value} ? $self->l( $arg_r->{value} ) : $self->perr('value'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $value_hr = $storage->set_value( { scope => $scope, # scope referencing objects escope => $escope, # scope referencing attributes (e=erase) changes => $changes, type => $type, obj => $object, value => $value, attr_ar => [ %{$attrvalue_hr} ] } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_add_node | # +----------------------------------------------------------------------+ sub cipux_storage_add_node { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my %merged = ( %{$attrvalue_hr}, %{$mattrvalue_hr} ); # If to print that out, better not relay on Data::Dumper # if ($debug) { # my $c = Data::Dumper->new( [ \%merged ], ['*merged'] ); # $c->Varname('merged'); # $c->Purity(1); # $c->Deepcopy(1); # print q{=} x 56, "\n"; # print "\n" . $c->Dump; # print q{=} x 56, "\n"; # } ## end if($debug) my $value_hr = $storage->add_node( { type => $type, obj => $object, attr_hr => \%merged } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_rename_node | # +----------------------------------------------------------------------+ sub cipux_storage_rename_node { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); my $value = exists $arg_r->{value} ? $self->l( $arg_r->{value} ) : $self->perr('value'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $value_hr = $storage->rename_node( { type => $type, obj => $object, value => $value } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | cipux_storage_delete_node | # +----------------------------------------------------------------------+ sub cipux_storage_delete_node { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $object = exists $arg_r->{object} ? $self->l( $arg_r->{object} ) : $self->perr('object'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $value_hr = $storage->delete_node( { type => $type, obj => $object, } ); # +------------------------------------------------------------------+ # | API return; } # +----------------------------------------------------------------------+ # | _print_values | # +----------------------------------------------------------------------+ sub _print_values : PRIVATE { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); my $pretty = exists $arg_r->{pretty} ? $self->l( $arg_r->{pretty} ) : $self->perr('pretty'); my $value_hr = exists $arg_r->{value_hr} ? $self->h( $arg_r->{value_hr} ) : $self->perr('value_hr'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'scope: ', $scope ); $logger->debug( 'pretty: ', $pretty ); $logger->debug( 'value_hr: ', { filter => \&Dumper, value => $value_hr } ); if ($pretty) { my $mc1 = 0; # max col ID my $mc2 = 0; # max col ATTR my $mc3 = 0; # max col VALUE my $width = 0; # calculate max count of attribute my $z = 0; # counts attr foreach my $attr ( keys %{$attrvalue_hr} ) { $z++; # this will count only given attr } # one OID, scope = one: # l=1 => VALUE :1 val, 1 attr, only value printed # l=4 => ATTR|VALUE :1 val, x attr, attr + value printed # # many OID, scope = all: # l=2 => OID|VALUE| :1 val, 1 attr, no need to print attr # l=3 => OID|ATTR |VALUE :1 val, x attr, x oid # # l=layout # my $layout = ( $z < 2 and $scope eq 'one' ) ? 1 : ( $z < 2 and $scope eq 'all' ) ? 2 : ( $z >= 2 and $scope eq 'all' ) ? 3 : 4; # type 4 # count of columns my $col = ( $layout == 1 ) ? 1 : ( $layout == 2 ) ? 2 : ( $layout == 3 ) ? 3 : ( $layout == 4 ) ? 2 : 2; # calculate max column width foreach my $oid ( sort keys %{$value_hr} ) { my $v = 'NULL'; foreach my $attr ( keys %{ $value_hr->{$oid} } ) { if ( defined $value_hr->{$oid}->{$attr} ) { $v = join '; ', @{ $value_hr->{$oid}->{$attr} }; } if ( $mc1 < length $oid ) { $mc1 = length $oid; } if ( $mc2 < length $attr ) { $mc2 = length $attr; } if ( $mc3 < length $v ) { $mc3 = length $v; } } } # col = 1 => c+2 # col = 2 => a+c+5, b+c+5 # col = 3 => a+b+c+8 $width = ( $layout == 1 ) ? $mc3 + ( $col * 2 + $col - 1 ) : ( $layout == 2 ) ? $mc1 + $mc3 + ( $col * 2 + $col - 1 ) : ( $layout == 3 ) ? $mc1 + $mc2 + $mc3 + ( $col * 2 + $col - 1 ) : ( $layout == 4 ) ? $mc2 + $mc3 + ( $col * 2 + $col - 1 ) : 0; $logger->debug( 'ATTR : ', $z ); $logger->debug( 'COL : ', $col ); $logger->debug( 'LAYOUT: ', $layout ); $logger->debug( 'mc1 : ', $mc1 ); $logger->debug( 'mc2 : ', $mc2 ); $logger->debug( 'mc3 : ', $mc3 ); $logger->debug( 'width : ', $width ); # print header print q{+} . q{-} x $width . "+\n"; print $self->_row( { layout => $layout, pretty => $pretty, value => [ 'ID', 'ATTR', 'VALUE' ], max => [ $mc1, $mc2, $mc3 ] } ); print q{+} . q{=} x $width . "+\n"; foreach my $oid ( sort keys %{$value_hr} ) { my $v = 'NULL'; foreach my $attr ( keys %{ $value_hr->{$oid} } ) { if ( defined $value_hr->{$oid}->{$attr} ) { $v = join ', ', @{ $value_hr->{$oid}->{$attr} }; } if ( defined $attrvalue_hr->{$attr} ) { print $self->_row( { layout => $layout, max => [ $mc1, $mc2, $mc3 ], value => [ $oid, $attr, $v ], pretty => $pretty } ); } } } print q{+} . q{-} x $width . "+\n"; } else { $logger->debug('Non pretty output: '); my $z = 0; foreach my $attr ( keys %{$attrvalue_hr} ) { $z++; # this will count only given attr } $logger->debug( 'attr count: ', $z ); $logger->debug( 'scope: ', $scope ); foreach my $oid ( sort keys %{$value_hr} ) { $logger->debug( 'oid: ', $oid ); my $v = 'NULL'; foreach my $attr ( keys %{ $value_hr->{$oid} } ) { $logger->debug( 'attr: ', $attr ); if ( defined $value_hr->{$oid}->{$attr} ) { $v = join q{ }, @{ $value_hr->{$oid}->{$attr} }; } #$logger->debug( 'attr2: ',$attrvalue_hr->{$attr} ,"\n"); # next if not defined $attrvalue_hr->{$attr}; if ( $z < 2 and $scope eq 'one' ) { # one value with one attribute printf "%s\n", $v; } else { # more the one value: (1) attr > 1 or (2) obj > 1 if ( $scope eq 'all' ) { # do not print cn or oid line # OID\tVALUE if ( $z < 2 ) { # with one attr, we do not have to print it printf "%s\t%s\n", $oid, $v; } else { printf "%s\t%s\t%s\n", $oid, $attr, $v; } } else { # do not print cn or oid line # ATTR\tVALUE printf "%s\t%s\n", $attr, $v; } } } } } # +------------------------------------------------------------------+ # | API return; } # +======================================================================+ # || _list_type || # +======================================================================+ sub _print_list_type : PRIVATE { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $cfg = exists $arg_r->{cfg} ? $self->l( $arg_r->{cfg} ) : $self->perr('cfg'); my $pretty = exists $arg_r->{pretty} ? $self->l( $arg_r->{pretty} ) : $self->perr('pretty'); # +------------------------------------------------------------------+ # | main my $storage = CipUX::Storage->new(); my $list_ar = $storage->list_type(); # output # # foreach my $line (@$list_ar){ # chomp($line); # print "$line\n"; # } # mostly this stuff is for pretty print my $max_col = 0; my $width = 0; if ($pretty) { foreach my $line ( @{$list_ar} ) { if ( $max_col < length $line ) { $max_col = length $line; } } $width = 2 + $max_col; print q{+}, q{-} x $width, "+\n"; printf '| %-' . $max_col . "s |\n", 'storage type'; print q{+}, q{=} x $width, "+\n"; } ## end if($pretty) foreach my $line ( @{$list_ar} ) { chomp $line; if ($pretty) { printf '| %-' . $max_col . "s |\n", $line; } else { print "$line\n"; } } ## end foreach my $line (@$list_ar) if ($pretty) { print q{+}, q{-} x $width, "+\n"; } # +------------------------------------------------------------------+ # | API return; } # +======================================================================+ # || _row || # +======================================================================+ sub _row : PRIVATE { # API my ( $self, $arg_r ) = @_; my $pretty = $arg_r->{pretty} || 0; # 0|1 pretty print my $layout = $arg_r->{layout} || 2; # layout 1..4 my $mymaxcol_ar = $arg_r->{max} || (); # max colum width my $myvalue_ar = $arg_r->{value} || (); # max colum width # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug( 'pretty: ', $pretty ); $logger->debug( 'layout: ', $layout ); # one OID, scope = one # l=1 => VALUE :1 val, 1 attr, only value printed # l=4 => ATTR| VALUE :1 val, x attr, attr + value printed # many OID, scope = all # l=2 => OID|VALUE| :1 val, 1 attr, no need to print attr # l=3 => OID|ATTR |VALUE :1 val, x attr, x oid # # l=layout # my $c1 = ${ $mymaxcol_ar->[0] } || 0; my $c2 = ${ $mymaxcol_ar->[1] } || 0; my $c3 = ${ $mymaxcol_ar->[2] } || 0; my $v1 = ${ $myvalue_ar->[0] } || 0; my $v2 = ${ $myvalue_ar->[1] } || 0; my $v3 = ${ $myvalue_ar->[2] } || 0; my $l = ($pretty) ? '| ' : $EMPTY_STRING; # left border my $r = ($pretty) ? ' |' : $EMPTY_STRING; # right border my $m = ($pretty) ? ' | ' : $EMPTY_STRING; # middle line my $v = "%-${c3}s"; # value my $t = "%-${c2}s"; # attr my $o = "%-${c1}s"; # oid $logger->debug( 'c1: ', $c1 ); $logger->debug( 'c2: ', $c2 ); $logger->debug( 'c3: ', $c3 ); $logger->debug( 'l: ', $l ); $logger->debug( 'r: ', $r ); $logger->debug( 'm: ', $m ); my $row = ( $layout == 1 ) ? sprintf( "$l$v$r", $v3 ) : ( $layout == 2 ) ? sprintf( "$l$o$m$v$r", $v1, $v3 ) : ( $layout == 3 ) ? sprintf( "$l$o$m$t$m$v$r", $v1, $v2, $v3 ) : ( $layout == 4 ) ? sprintf( "$l$o$m$v$r", $v2, $v3 ) : "$l$r"; # +------------------------------------------------------------------+ # | API return $row . "\n"; } } # END INSIDE-OUT CLASS 1; __END__ =pod =head1 NAME CipUX::Storage::Client - Command line client library for CipUX-Storage =head1 VERSION version 3.4.0.2 =head1 SYNOPSIS use CipUX::Storage::Client; my $c = CipUX::Storage::Client->new( { name => 'cipux_storage_client' } ); $c->run(); =head1 DESCRIPTION Provides the functions get_value, set_value to modify LDAP attribute values. The function add_node, delete_node and rename_node for adding, deleting and renaming LDAP objects. =head1 SUBROUTINES/METHODS The following functions will be exported by CipUX::Storage::Client. =head2 new Constructor B my $storage = CipUX::Storage::Client->new({}); =head2 cipux_storage_add_node Wrapper subroutine for CipUX::Storage->add_node. =head2 cipux_storage_delete_node Wrapper subroutine for CipUX::Storage->delete_node. =head2 cipux_storage_get_all_values Wrapper subroutine for CipUX::Storage->get_all_values. =head2 cipux_storage_get_value Wrapper subroutine for CipUX::Storage->get_value. =head2 cipux_storage_list Wrapper subroutine for CipUX::Storage->print_list. =head2 cipux_storage_rename_node Wrapper subroutine for CipUX::Storage->rename_node. =head2 cipux_storage_set_all_values Wrapper subroutine for CipUX::Storage->set_all_values. =head2 cipux_storage_set_value Wrapper subroutine for CipUX::Storage->set_value. =head2 run Initialize the library. Should be caleld by a script. =head1 CONFIGURATION AND ENVIRONMENT See cipux-storage-access.conf and cipux-storage-structure.conf man page for details on configuration. CipUX::Storage do not use the environment for configuration. =head1 DEPENDENCIES Carp Class::Std; CipUX CipUX::Storage Data::Dumper English Getopt::Long Log::Log4perl Pod::Usage Readonly =head1 INCOMPATIBILITIES Not known. =head1 BUGS AND LIMITATIONS Not known. =head1 SEE ALSO See the CipUX web page and the manual at L See the mailing list L =head1 AUTHOR Christian Kuelker Echristian.kuelker@cipworx.orgE =head1 LICENSE AND COPYRIGHT Copyright (C) 2007 - 2009 by Christian Kuelker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut CipUX-Storage-3.4.0.2/lib/CipUX/Storage.pm0000444000175000017500000013751111237647212020157 0ustar ckuelkerckuelker# +==========================================================================+ # || CipUX::Storage || # || || # || CipUX storage abstraction layer || # || || # || Copyright (C) 2007 - 2009 by Christian Kuelker. All rights reserved! || # || || # || License: GNU GPL version 2 or any later version. || # || || # +==========================================================================+ # ID: $Id$ # Revision: $Revision$ # Head URL: $HeadURL$ # Date: $Date$ # Source: $Source$ package CipUX::Storage; use 5.008001; use strict; use warnings; use utf8; use Carp; use Class::Std; use Data::Dumper; use English qw( -no_match_vars); use Log::Log4perl qw(:easy); use Net::LDAP; use Readonly; use base qw(CipUX); { # BEGIN CLASS use version; our $VERSION = qv('3.4.0.2'); use re 'taint'; # Keep tainted any data captured by parens delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; # Make %ENV safe # +======================================================================+ # || CONST || # +======================================================================+ Readonly::Scalar my $EMPTY_STRING => q{}; # TODO: make the global configurable Readonly::Scalar my $MIN_OID_NUMBER => 10101; ## no critic (RequireNumberSeparators) # +======================================================================+ # || OBJECT || # +======================================================================+ my %storage_cfg : ATTR( :get ); my %access_cfg : ATTR( :get ); # +======================================================================+ # || GLOBAL || # +======================================================================+ my $schema = undef; # contains LDAP schema if add_node # exception messages # +======================================================================+ # || CONSTRUCTOR || # +======================================================================+ sub BUILD { # +------------------------------------------------------------------+ # | API my ( $self, $ident, $arg_r ) = @_; # add prefix for cfg, if needed my $pref = exists $arg_r->{pref} ? $self->l( $arg_r->{pref} ) : $EMPTY_STRING; my $cache_dir = exists $arg_r->{cache_dir} ? $self->l( $arg_r->{cache_dir} ) : $EMPTY_STRING; # +------------------------------------------------------------------+ # | main my $cfg_hr = $self->cfg( { 'sub' => 'storage', pref => $pref, cache_dir => $cache_dir } ); $storage_cfg{$ident} = $cfg_hr->{structure}; my $access_cfg_hr = $self->cfg( { 'sub' => 'access', pref => $pref, cache_dir => $cache_dir } ); $access_cfg{$ident} = $access_cfg_hr->{ldap}; # +------------------------------------------------------------------+ # | API return; } # +======================================================================+ # || DESTRUCTOR || # +======================================================================+ sub DEMOLISH { # +------------------------------------------------------------------+ # | API my ( $self, $ident ) = @_; # +------------------------------------------------------------------+ # | main delete $storage_cfg{$ident}; delete $access_cfg{$ident}; undef $schema; # +------------------------------------------------------------------+ # | API return; } # +======================================================================+ # || open module features || # +======================================================================+ # +======================================================================+ # || get_value || # +======================================================================+ sub get_value { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $obj = ( exists $arg_r->{obj} and defined $arg_r->{obj} ) ? $self->l( $arg_r->{obj} ) : q{*}; my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); # one|all my $filter = exists $arg_r->{filter} ? $self->l( $arg_r->{filter} ) : $EMPTY_STRING; my $attr_ar = exists $arg_r->{attr_ar} ? $self->a( $arg_r->{attr_ar} ) : []; # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> obj: ', $obj ); $logger->debug( '> obj: ', { filter => \&Dumper, value => $obj } ); $logger->debug( '> type: ', $type ); $logger->debug( '> scope: ', $scope ); $logger->debug( '> filter: ', $filter ); $logger->debug( '> attr_ar: ', { filter => \&Dumper, value => $attr_ar } ); # calc rel values my $ldap_hr = $self->_ldap_struct( { type => $type, scope => $scope, obj => $obj, filter => $filter } ); my $sattr_ar = []; push @{$sattr_ar}, @{$attr_ar}; push @{$sattr_ar}, $ldap_hr->{dn_attr}; # add: uid|cn my $ldap = $self->_ldap_start(); my $rslt = $ldap->search( base => $ldap_hr->{search}, deref => 'always', attrs => $sattr_ar, filter => $ldap_hr->{filter} . $filter ); # if the search went wrong my $msg = 'Search failed! '; $msg .= " base [$ldap_hr->{search}] "; $msg .= " filter [$ldap_hr->{filter}] "; if ( $rslt->code ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } $self->_ldap_end( { ldap => $ldap } ); my %ret = (); foreach my $entry ( $rslt->entries ) { foreach my $attr ( $entry->attributes ) { push @{ $ret{ $entry->get_value( $ldap_hr->{dn_attr} ) } {$attr} }, $entry->get_value($attr); } } $logger->debug( 'ret: ', { filter => \&Dumper, value => \%ret } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return \%ret; } ## end sub get_value # +=======================================================================+ # || set_value || # +=======================================================================+ sub set_value { ## no critic (ProhibitExcessComplexity) # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $obj = ( exists $arg_r->{obj} and defined $arg_r->{obj} ) ? $self->l( $arg_r->{obj} ) : q{*}; # add|delete|replace my $changes = exists $arg_r->{changes} ? $self->l( $arg_r->{changes} ) : $self->perr('changes'); my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : $self->perr('scope'); # one|all my $escope = exists $arg_r->{escope} ? $self->l( $arg_r->{escope} ) : 'none'; # one|all|none my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $value = exists $arg_r->{value} ? $self->l( $arg_r->{value} ) : $EMPTY_STRING; my $attr_ar = exists $arg_r->{attr_ar} ? $self->a( $arg_r->{attr_ar} ) : $self->perr('attr_ar'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> obj: ', $obj ); $logger->debug( '> changes: ', $changes ); $logger->debug( '> scope: ', $scope ); $logger->debug( '> escope: ', $escope ); $logger->debug( '> type: ', $type ); $logger->debug( '> value: ', $value ); $logger->debug( '> attr_ar: ', { filter => \&Dumper, value => $attr_ar } ); # calc rel values my $ldap_hr = $self->_ldap_struct( { type => $type, obj => $obj, scope => $scope } ); my $ldap = $self->_ldap_start(); # prepare all to-be-stored attribute => value pairs my $target_ar = []; if ( defined $value and $value ne $EMPTY_STRING ) { foreach my $attr ( @{$attr_ar} ) { # [ $attribute => $value ] # push( @{$target_ar}, { $attr => $value } ); # [ $attribute => $value ] if ( defined $value and $value ne $EMPTY_STRING and defined $attr and $attr ne $EMPTY_STRING ) { push @{$target_ar}, $attr => $value; $logger->debug( 'add attr: ', $attr ); $logger->debug( 'add value: ', $value ); } else { my $msg = 'EXC: tried to add empty value or attr!'; $logger->debug($msg); } } ## end foreach my $attr ( @{$attr_ar... } else { $target_ar = $attr_ar; } if ( $scope eq 'all' ) { # get all uid|cn my $obj_id_hr = $self->get_value( { scope => 'all', type => $type, obj => $obj, attr_ar => [ $ldap_hr->{dn_attr} ] } ); # over all uid|cn foreach my $oid ( sort keys %{$obj_id_hr} ) { $logger->debug( 'oid: ', $oid ); my $dn = "$ldap_hr->{dn_attr}="; $dn .= "$oid,$ldap_hr->{struc_rdn}," . $access_cfg{ ident $self}->{base_dn}; $logger->debug( 'dn: ', $dn ); my $rslt = $ldap->modify( $dn, changes => [ $changes => $target_ar ] ); my $msg = "Can not change entry [$dn]!"; if ( $rslt->codei ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } } ## end foreach my $oid ( sort keys... } else { # scope one my $dn = "$ldap_hr->{dn_attr}="; $dn .= "$obj,$ldap_hr->{struc_rdn}," . $access_cfg{ ident $self}->{base_dn}; $logger->debug( 'dn: ', $dn ); $logger->debug( 'changes: ', $changes ); # build an array for LDAP attribute deletion my @del_target = (); if ( $escope eq 'all' ) { foreach my $attr ( @{$target_ar} ) { # remove unneeded entries if ( ref($attr) ne 'ARRAY' ) { push @del_target, $attr; } } } ## end if ( $escope eq 'all' ) $logger->debug( 'target_ar: ', { filter => \&Dumper, value => $target_ar } ); $logger->debug( 'del_target array: ', { filter => \&Dumper, value => \@del_target } ); my $rslt = undef; if ( $escope eq 'all' ) { # erase all entries of an attribute $rslt = $ldap->modify( $dn, delete => \@del_target ); } else { # make an ordinary change|delete|add $rslt = $ldap->modify( $dn, changes => [ $changes => $target_ar ] ); } my $msg = "Can not change entry [$dn]!"; if ( $rslt->code ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } } ## end else [ if ( $scope eq 'all' ) $self->_ldap_end( { ldap => $ldap } ); # +------------------------------------------------------------------+ # | API return; } ## end sub set_value # +======================================================================+ # || add_node || # +======================================================================+ sub add_node { ## no critic (ProhibitExcessComplexity) # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $obj = ( exists $arg_r->{obj} and defined $arg_r->{obj} ) ? $self->l( $arg_r->{obj} ) : $self->perr('obj'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $attr_hr = exists $arg_r->{attr_hr} ? $self->h( $arg_r->{attr_hr} ) : $self->perr('attr_hr'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> obj: ', $obj ); $logger->debug( '> type: ', $type ); $logger->debug( '> attr_hr: ', { filter => \&Dumper, value => $attr_hr } ); # calc rel values my $ldap_hr = $self->_ldap_struct( { type => $type, obj => $obj } ); # initialize the communication with LDAP my $ldap = $self->_ldap_start(); # collect data about auxiliary and mandatory attributes. if this # becomes a performance issue, it could perhaps be done only once # a day or once a startup. But add is a rather seldom operation # compared to set and get, so is probably OK to do on every # invocation, as then the information is ensured to be valid # every time. my @mandatory_attr = (); my %mandatory_attr = (); my %given_attr = (); my %auxillary_attr = (); # get the schema for making checks if ( not defined $schema ) { $logger->debug('retrieve schema from LDAP'); $schema = $ldap->schema; } else { my $msg = 'LDAP schema already there, will not retrieve'; $logger->debug($msg); } # copy the hash to $cattr_ar my $cattr_ar = (); # copy of data to give Net::LDAP->add # $schema->dump(); foreach my $attr ( sort keys %{$attr_hr} ) { $logger->debug( 'attr: ', $attr ); # unfortunately we have to make a copy, because: # (1) the hash or hashref cannot be passed to Net::LDAP->add # (2) only the hash or hashref can be analyzed # So the trick is to parse the hash but commit the array reference. # This module has not the duty to correct the hash. It was done by # CipUX::Object, hopefully. # But this module has the duty to croak if it can be forseen that # somethings is wrong or missing. # And it will throw an exception if somthing went wrong. push @{$cattr_ar}, $attr; push @{$cattr_ar}, $attr_hr->{$attr}; if ( $attr eq 'objectClass' ) { $logger->debug( '-> found obj.Class: ', $attr ); # go over every objectClass ($oc) foreach my $oc ( @{ $attr_hr->{$attr} } ) { # Nice try LDAP-kun, but this is too obvious! next if $oc eq 'top'; my $msg = '-> found obj.Class name'; $logger->debug( $msg . q{: }, $oc ); # remember mandatory my @must = $schema->must($oc); push @mandatory_attr, @must; # go over every mandatory attribute ($n) not objectClass foreach my $n (@must) { # Dear LDAP-kun, this is obvious too. next if $n->{name} eq 'objectClass'; # remember mandatory $mandatory_attr{ $n->{name} } = 1; my $msg2 = '--> mandatory attr'; $logger->debug( $msg2 . q{: }, $n->{name} ); } ## end foreach my $n (@must) my @may = $schema->may($oc); # go over all optional attributes # First optional attr has the name '$may[0]->{name}' foreach my $n (@may) { # remember optional $auxillary_attr{ $n->{name} } = 1; my $msg3 = '--> auxillary attr'; $logger->debug( $msg3 . q{: }, $n->{name} ); } ## end foreach my $n (@may) } ## end foreach my $oc ( @{ $attr_hr... } else { $logger->debug( '-> generic attribute: ', $attr ); # remember given non objectClasses with value $given_attr{$attr} = $attr_hr->{$attr}; } ## end else [ if ( $attr eq 'objectClass') } ## end foreach my $attr ( sort keys... # check 1: # check given data for add: croak if 'not possible attr' are given foreach my $attr ( sort keys %{$attr_hr} ) { $logger->debug( 'check attr: ', $attr ); if ( $mandatory_attr{$attr} or $attr eq 'objectClass' ) { $logger->debug( '-> attr mandatory: OK: ', $attr ); } elsif ( $auxillary_attr{$attr} ) { $logger->debug( '-> attr auxillary: OK: ', $attr ); } else { my $msg = '-> EXCEPTION: given attribute not possible!'; $logger->debug( $msg . q{: }, $attr ); if ( $attr eq $EMPTY_STRING ) { $self->exc( { msg => 'EXCEPTION given attr was empty!' } ); } $msg = "The given attr [$attr] is not valid "; $msg .= 'for the given object classes. Add is not possible! '; $msg .= '(If you have not given the right objectClass, then '; $msg .= 'this is the reason why it is not possible!)'; $msg .= 'So please check given objectClass or attribute.'; $self->exc( { msg => $msg } ); } ## end else [ if ( $mandatory_attr{$attr... } ## end foreach my $attr ( sort keys... # check 2: # check given data for add: if all mandatory attr are given # croak if attribute is missing foreach my $attr ( sort @mandatory_attr ) { my $n = $attr->{name}; $logger->debug( 'check mandatory attr: ', $n ); if ( defined $attr_hr->{$n} ) { $logger->debug( '-> mandatory attr OK: ', $n ); } else { my $msg = '-> EXCEPTION: mandatory attribute not given!'; $logger->debug( $msg . q{: }, $n ); $msg = "EXCEPTION mandatory attr [$n] is missing!"; $msg .= ' Please provide -x or --mattrvalue command line'; $msg .= " option! Example: -x $n="; $self->exc( { msg => $msg } ); } ## end else [ if ( defined $attr_hr->... } ## end foreach my $attr ( sort @mandatory_attr) $logger->debug( 'cattr_ar: ', { filter => \&Dumper, value => $cattr_ar } ); # commit the stuff my $rslt = $ldap->add( $ldap_hr->{dn}, attr => $cattr_ar ); my $msg = "Can not add entry [$ldap_hr->{dn}]!"; if ( $rslt->code ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } $self->_ldap_end( { ldap => $ldap } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $rslt; } ## end sub add_node # +======================================================================+ # || delete_node || # +======================================================================+ sub delete_node { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $obj = ( exists $arg_r->{obj} and defined $arg_r->{obj} ) ? $self->l( $arg_r->{obj} ) : $self->perr('obj'); my $type = ( exists $arg_r->{type} and defined $arg_r->{type} ) ? $self->l( $arg_r->{type} ) : $self->perr('type'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> obj: ', $obj ); $logger->debug( '> type: ', $type ); $logger->debug( 'self:', { filter => \&Dumper, value => $self } ); $logger->debug( 'ident:', { filter => \&Dumper, value => ident $self } ); # calc rel value my $ldap_hr = $self->_ldap_struct( { type => $type, obj => $obj } ); $logger->debug( 'ldap_hr: ', { filter => \&Dumper, value => $ldap_hr } ); # start the LDAP communication $logger->debug('starting communication ...'); my $ldap = $self->_ldap_start(); # delete the object $logger->debug('issue delete command ...'); my $rslt = $ldap->delete( $ldap_hr->{dn} ); # throw an exception if something went wrong my $msg = "Can not delete entry [$ldap_hr->{dn}]!"; if ( $rslt->code ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } # terminate LDAP communication $logger->debug('terminate communication ...'); $self->_ldap_end( { ldap => $ldap } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $rslt; } ## end sub delete_node # +======================================================================+ # || rename_node || # +======================================================================+ sub rename_node { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $obj = exists $arg_r->{obj} and defined $arg_r->{obj} ? $self->l( $arg_r->{obj} ) : $self->perr('obj'); my $value = exists $arg_r->{value} ? $self->l( $arg_r->{value} ) : $self->perr('value'); my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> obj: ', $obj ); $logger->debug( '> value: ', $value ); $logger->debug( '> type: ', $type ); # calc rel values my $ldap_hr = $self->_ldap_struct( { type => $type, obj => $obj } ); # calculating relative DN my $rdn = $ldap_hr->{dn_attr} . q{=} . $value; $logger->debug( 'new rdn: ', $rdn ); # start LDAP communication my $ldap = $self->_ldap_start(); # do the modification my $rslt = $ldap->moddn( $ldap_hr->{dn}, newrdn => $rdn ); # throw an exception if something went wrong my $msg = "Can not modify entry [$ldap_hr->{dn}]!"; if ( $rslt->code ) { $self->exc( { msg => "$msg (" . $rslt->error . ')' } ); } # terminate LDAP communication $self->_ldap_end( { ldap => $ldap } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $rslt; } ## end sub rename_node # +======================================================================+ # || get_sid || # +======================================================================+ sub get_sid { # +------------------------------------------------------------------+ # | API my $self = shift; my $sattr_ar = []; my $ldap = $self->_ldap_start(); my $rslt = $ldap->search( base => $access_cfg{ ident $self}->{base_dn}, deref => 'always', scope => 'one', attrs => ['sambaSID'], # FIXME: replace this hardcoded value with configfile lookup filter => '(sambaDomainname=skolelinux)' ); if ( $rslt->code ) { $self->exc( { msg => q{ (} . $rslt->error . q{)} } ); } $self->_ldap_end( { ldap => $ldap } ); my @entry = $rslt->entries; # +------------------------------------------------------------------+ # | API return $entry[0]->get_value('sambaSID'); } ## end sub get_sid # +======================================================================+ # || _ldap_start || # +======================================================================+ sub _ldap_start : PRIVATE { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; # global API my $uri = $access_cfg{ ident $self}->{uri}; my $bind_dn = $access_cfg{ ident $self}->{bind_dn}; my $password = $access_cfg{ ident $self}->{password}; # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'uri: ', $uri ); $logger->debug( 'bind_dn: ', $bind_dn ); if ( not defined $password ) { my $msg = '(EXCEPTION): password is not defined'; $msg .= " in cipux-access.ini or similar file.\n"; croak $msg; } #$logger->debug( "password: [$password]" ); my $msg = 'Can not create Net::LDAP object with URI [' . $uri . ']. '; # new connection my $ldap = Net::LDAP->new($uri) or $self->exc( { msg => "$msg $@" } ); # bind to LDAP $msg = $ldap->bind( $bind_dn, password => $password ); if ( $msg->code ) { $self->exc( { msg => "Can not bind to LDAP server! ($msg->error)" } ); } $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $ldap; } ## end sub _ldap_start # +======================================================================+ # || _ldap_end || # +======================================================================+ sub _ldap_end : PRIVATE { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; # TODO: find out what ref and make a CipUX h/a call my $ldap = exists $arg_r->{ldap} ? $arg_r->{ldap} : $self->perr('ldap'); # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( 'ldap: ', $ldap ); my $msg = $ldap->unbind; # take down tie if ( $msg->code ) { $self->exc( { msg => "Can not unbind from LDAP server! ($msg->error)" } ); } $msg = $ldap->disconnect; # take down session $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $msg; } ## end sub _ldap_end # +======================================================================+ # || list_storage_type || # +======================================================================+ sub list_storage_type { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); # we want only the keys (type names) my @return = sort keys %{ $storage_cfg{ ident $self} }; $logger->debug( 'list_storage_type return: ', { filter => \&Dumper, value => \@return } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return \@return; } # +======================================================================+ # || _ldap_struct || # +======================================================================+ sub _ldap_struct : PRIVATE { ## no critic (ProhibitExcessComplexity) # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; my $type = exists $arg_r->{type} ? $self->l( $arg_r->{type} ) : $self->perr('type'); my $obj = exists $arg_r->{obj} ? $self->l( $arg_r->{obj} ) : undef; my $scope = exists $arg_r->{scope} ? $self->l( $arg_r->{scope} ) : undef; my $filter = exists $arg_r->{filter} ? $self->l( $arg_r->{filter} ) : undef; # +------------------------------------------------------------------+ # | main my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); $logger->debug( '> type: ', $type ); if ( defined $obj ) { $logger->debug( '> obj: ', $obj ); } if ( defined $scope ) { $logger->debug( '> scope: ', $scope ); } if ( defined $filter ) { $logger->debug( '> filter: ', $filter ); } $logger->debug( 'self:', { filter => \&Dumper, value => $self } ); $logger->debug( 'ident:', { filter => \&Dumper, value => ident $self } ); #my $cfg_structure_hr = $self->get_storage_cfg(); my $cfg_structure_hr = $storage_cfg{ ident $self}; #$cfg_structure_hr = $cfg_structure_hr->{structure}; #$logger->debug( 'cfg_structure_hr:', # { filter => \&Dumper, value => $cfg_structure_hr } ); # test type for all subs: my $type_ar = $self->list_storage_type( { cfg_structure_hr => $cfg_structure_hr } ); #$logger->info( 'type_ar:', # { filter => \&Dumper, value => $type_ar } ); my %type = (); foreach my $t ( @{$type_ar} ) { $type{$t} = 1; } my $list_type = join ', ', @{$type_ar}; my $cfg1 = defined( $access_cfg{ ident $self}->{access_cfg} ) ? $access_cfg{ ident $self}->{access_cfg} : 'undef'; if ( not defined $type{$type} ) { my $msg = "type [$type], specified by option -t or --type, "; $msg .= 'is not defined in configuration file '; $msg .= "[$cfg1]! "; $msg .= "Valid types are: [$list_type]"; $self->exc( { msg => $msg } ); } ## end if ( not defined $type... my %ldap = (); # relative values to $access_cfg{ident $self}->{structure} and $type #my $clc_hr = $$storage_cfg{ident $self}{ 'structure' }->{$type}; my $clc_hr = $storage_cfg{ ident $self}->{$type}; my $msg1 = 'Undefined variable [dn_attr] in configuration '; $msg1 .= 'space [cipux-storage.*]! Please edit the file '; $msg1 .= 'and give it a value.'; $ldap{dn_attr} = $self->l( $clc_hr->{dn_attr} ) || $self->exc( { msg => $msg1 } ); $msg1 = 'Undefined variable [filter] in configuration '; $msg1 .= 'space [cipux-storage.*]! Please edit the file '; $msg1 .= 'and give it a value.'; $ldap{filter} = $self->lf( $clc_hr->{filter} ) || $self->exc( { msg => $msg1 } ); $msg1 = 'Undefined variable [struc_rdn] in configuration '; $msg1 .= 'file [cipux-storage.*]! Please edit the file '; $msg1 .= 'and give it a value.'; #$ldap{struc_rdn} = $self->l( $clc_hr->{struc_rdn} ) # || $self->exc( { msg => $msg } ); $ldap{struc_rdn} = $self->l( $clc_hr->{struc_rdn} ) || $EMPTY_STRING; $logger->debug( ' dn_attr: ', $ldap{dn_attr} ); #$logger->debug(' filter: ', $ldap{filter} ,"\n"); $logger->debug( ' struc_rdn: ', $ldap{struc_rdn} ); my @search = (); if ( $ldap{struc_rdn} ne $EMPTY_STRING ) { push @search, $ldap{struc_rdn}; } if ( $access_cfg{ ident $self}->{base_dn} ne $EMPTY_STRING ) { push @search, $access_cfg{ ident $self}->{base_dn}; } $ldap{search} = $ldap{struc_rdn} . q{,} . $access_cfg{ ident $self}->{base_dn}; $ldap{search} = join q{,}, @search; $logger->debug( ' search: ', $ldap{search} ); if ( defined $obj ) { unshift @search, $obj; $ldap{dn} = "$ldap{dn_attr}="; # $ldap{dn} .= "$obj,"; # $ldap{dn} .= "$ldap{struc_rdn},"; # $ldap{dn} .= "$access_cfg{ident $self}->{base_dn}"; $ldap{dn} .= join q{,}, @search; $logger->debug( ' dn: ', $ldap{dn} ); } ## end if ( defined $obj ) if ( defined $scope ) { if ( not defined $obj ) { $self->perr('obj (needed for scope)'); } if ( $scope eq 'one' ) { $ldap{filter} =~ s/\?/$obj/gmsx; } elsif ( $scope eq 'all' ) { $ldap{filter} =~ s/\?/\*/gmsx; } else { my $msg2 = 'The value of the variable "scope" in methode '; $msg2 .= 'should be "all" or "one"! Please give an '; $msg2 .= 'apropriate value.'; $self->exc( { $msg2 => $msg2 } ); } ## end else [ if ( $scope eq 'one' ) # additional filter from CipUX::Object or CipUX::Task if ( defined $filter ) { $logger->debug( 'add to filter: ', $filter ); $ldap{filter} .= $filter; } $logger->debug( 'mod filter: ', $ldap{filter} ); $logger->debug( 'scope: ', $scope ); } ## end if ( defined $scope ) $logger->debug( '< ldap struct: ', { filter => \&Dumper, value => \%ldap } ); $logger->debug('END'); # +------------------------------------------------------------------+ # | API return \%ldap; } ## end sub _ldap_struct # +======================================================================+ # || oid_number_supremum || # +======================================================================+ sub oid_number_supremum { # +------------------------------------------------------------------+ # | API my ( $self, $arg_r ) = @_; # +------------------------------------------------------------------+ # | prepare my $logger = get_logger(__PACKAGE__); $logger->debug('BEGIN'); my %oid_info = ( 'cipux_account.user' => 'uidNumber', 'cipux_account.group' => 'gidNumber', 'cipux_share.user' => 'uidNumber', 'cipux_share.group' => 'gidNumber', ); my $supremum = $MIN_OID_NUMBER; # +------------------------------------------------------------------+ # | main foreach my $cipux_object_type ( keys %oid_info ) { my $attr = $oid_info{$cipux_object_type}; my $scope = 'all'; my $type = $cipux_object_type; my $obj = q{*}; my $attrvalue_hr = { $attr => [], }; my $value_hr = $self->get_value( { scope => $scope, type => $type, obj => $obj, attr_ar => [ %{$attrvalue_hr} ] } ); $logger->debug("got storage $type"); $logger->debug( 'value_hr: ', { filter => \&Dumper, value => $value_hr } ); # 'testprof' => { # 'uid' => [ 'testprof' ], # 'uidNumber' => [ '11032' ] # } foreach my $oid ( keys %{$value_hr} ) { my $num = $value_hr->{$oid}->{$attr}->[0]; $logger->debug("Attribute: $attr"); $logger->debug("Number $num"); if ( not defined $supremum ) { $supremum = $num; } $supremum = $self->max( $supremum, $num ); } ## end foreach my $oid ( keys %{$value_hr... } ## end foreach my $cipux_object_type... $logger->debug('END'); # +------------------------------------------------------------------+ # | API return $MIN_OID_NUMBER if $supremum < $MIN_OID_NUMBER; return $supremum + 1; } ## end sub oid_number_supremum } # END INSIDE-OUT CLASS 1; __END__ =pod =for stopword CipUX LDAP openLDAP objectClass cipux perl cipuxAccount posixAccount destructor cipux-storage.perl uidNumber gidNumber sambaSID cipux-access.ini ldap uri debian TODO Readonly utf8 Kuelker =head1 NAME CipUX::Storage - Storage abstraction layer for CipUX =head1 VERSION version 3.4.0.2 =head1 SYNOPSIS use CipUX::Storage; =head1 DESCRIPTION The CipUX Storage abstraction layer is a generic abstract class, which can be used to access LDAP servers via Perl by issuing simple actions and via shell command line interface. It was tested with openLDAP version 3. The layer is capable of operating on different sets of LDAP nodes. A set of nodes might be defined by an LDAP objectClass or LDAP attribute. Example: cipuxAccount or posixAccount. The number of objects inside a set might be ranged from one to many. The abstraction layer performs a method on a set of nodes. Valid methods are: 'get', 'set', 'get-all', 'set-all' on LDAP attribute values and 'add', 'delete', 'rename' on LDAP nodes. It provides the functions get_value, set_value to modify LDAP attribute values. The function add_node, delete_node and rename_node for adding, deleting and renaming LDAP objects. =head1 SUBROUTINES/METHODS The following functions will be exported by CipUX::Storage. =head2 BUILD This is the constructor, see new. use CipUX::Storage; use base qw(CipUX::Storage); my $storage = CipUX::Storage->new(); =head2 DEMOLISH This is the destructor. =head2 get_value The get_value queries the LDAP and returns one ore more values depending on the parameter 'scope'. B eval { my $object = 'ckuelker'; my $attribute = 'cipuxFirstname'; my $type = 'all_user_node'; $value_hr = $ldap->get_value({ scope=>'one', type=>$type, obj=>$object, attr_ar=>[$attribute] }); } or croak "ERROR: can't get value: $@!" if $@; returns one value: %$ret_hr = ( 'ckuelker' => { 'cipuxFirstname' => ['Christian'], } ); eval { my $object = ''; my $attribute = 'cipuxFirstname'; my $type = 'all_user_node'; $value_hr = $ldap->get_value({ scope=>'all', type=>$type, obj=>$object, attr_ar=>[$attribute] }); } or croak "ERROR: can't get value: $@!" if $@; %$ret_hr = ( 'ckuelker' => { 'cipuxFirstname' => ['Christian'], 'cipuxLastname' => ['Kuelker'], }, 'xoswald' => { 'cipuxFirstname' => ['Xavier'], 'cipuxLastname' => ['Oswald'], }, ); =head3 Return values %ret = ( 'ckuelker' => { 'cipuxFirstname' => ['Christian'], 'cipuxLastname' => ['Kuelker'], } =head2 set_value Sets a value for a given object in the LDAP database. my $rslt = set_value( { obj=>$obj, attr_ar=>$attr_ar, changes=>$changes, scope=>$scope, escope=>$escope, type=>$type } ; obj: object attr_ar: reference to an array of LDAP attributes and values changes: scope: 'one|all' set/modify value escope: 'one|all|none' erase scope type: =head3 Modify Syntax my $msg = $ldap->modify( $dn, changes => [ # add sn=Baggins add => [ sn => 'Baggins' ], # delete all fax numbers delete => [ faxNumber => []], # delete phone number 911 delete => [ telephoneNumber => ['911']], # change email address replace => [ mail => 'bilbo@baggins.org'] ] ); =head2 add_node Adds an LDAP node to the LDAP database. my $rslt = $cipux->add_node({obj=>$obj, type=>$type, attr_hr=>$attr_hr}); obj : The object to be added type: kind of object to be added attr_hr: Hash reference with 'ldap_attribute=>value' structure $rslt: is the reslult from Net::LDAP add =head2 delete_node Deletes an LDAP node from the LDAP database. my $rslt = $cipux->delete_node( { obj=>$obj, type=>$type } ); obj : The object to be added type: kind of object to be added $rslt: is the result from Net::LDAP delete =head2 rename_node Rename an LDAP node of the LDAP database. my $rslt = $cipux->rename_node({obj=>$obj, type=>$type, value=>$value }); obj : The object to be added type: kind of object to be added value: The new name $rslt: is the result from Net::LDAP rename =head2 _ldap_start Binds to the LDAP server. my %access = (); $access_cfg{ident $self}->{uri} = 'ldap://localhost'; $access_cfg{ident $self}->{bind_dn} = 'cn=admin,dc=nodomain'; $access_cfg{ident $self}->{password} = 'secret'; my $ldap = $cipux->_ldap_start(); $ldap: is the LDAP Perl object returned from Net::LDAP. =head2 _ldap_start Unbinds from the LDAP server. my $msg = $cipux->_ldap_end( { ldap=>$ldap} ); $msg: is the message returned from Net::LDAP. =head2 list_storage_type Lists all CipUX LDAP nodes entities, sorted. my $list_ar = $cipux->list_type( { ldap=>$ldap} ); $list_ar: reference to an array of sorted CipUX LDAP entities. =head2 _ldap_struct Parses cipux-storage.perl with for object, type, filter of a given scope. It also performs some simple validation of that file. my $ldap_structure_hr = $cipux->_ldap_struct( { obj=>$obj, type=>$type, scope=>$scope, filter=>$filter }); $ldap_structure_hr: returns a structure hash reference =head2 oid_number_supremum Searches the storage database for uidNumber and gidNumber. It returns the one number above the largest number or the minimum number in the number range for users and groups. To perform the search it uses get_value (the storage layer itself). =head2 get_sid Retrieve sambaSID and return it if successful =head1 Configuration files =head2 cipux-access.ini The CipUX access configuration has the following entries: [ldap] uri = ldaps://ldap bind_dn = cn=cipuxroot,dc=nodomain base_dn = ou=CipUX,dc=nodomain password = secret system = debian customer = =head2 cipux_storage.perl The storage structure configuration might look like this: $cfg = { 'structure' => { all_group_node => { desc => 'access to all CN group objects', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '(cn=?)', }, all_user_node => { desc => 'access to all system UID objects', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '(uid=?)', }, course_group_node => { desc => 'access to all system GID objects', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(groupType=public)', }, }, } =head1 DIAGNOSTICS TODO =head1 CONFIGURATION AND ENVIRONMENT See cipux-access.ini and cipux-storage.perl man page for details on configuration. CipUX::Storage do not use the environment for configuration. =head1 DEPENDENCIES Carp Class::Std CipUX Data::Dumper English Net::LDAP Log::Log4perl Readonly utf8 version =head1 INCOMPATIBILITIES Not known. =head1 BUGS AND LIMITATIONS Not known. =head1 SEE ALSO See the CipUX web page and the manual at L See the mailing list L =head1 AUTHOR Christian Kuelker Echristian.kuelker@cipworx.orgE =head1 LICENSE AND COPYRIGHT Copyright (C) 2007 - 2009 by Christian Kuelker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut CipUX-Storage-3.4.0.2/lib/cipux-storage.perl.pod0000444000175000017500000000270311237647212021456 0ustar ckuelkerckuelker =pod =head1 cipux-storage.perl The CipUX storage layer comes with two configuration files. One for configuring basic values. This called typically cipux-storage.perl. The other holds the access data for the storage backend. Mostly called cipux-access.perl. This document describes cipux-storage.perl. Example: $cfg = { 'structure' => { 'cipux_ldap_orga_node' => { desc => 'access all CipUX LDAP orga nodes', struc_rdn => '', dn_attr => 'ou', filter => '&(ou=?)(objectClass=cipuxLdapOrgaNode)', }, 'cipux_account.user' => { desc => 'access all CipUX user account user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsAccount=TRUE)', }, }, }; =head2 $cfg Hold the storage node structural data. At the first level it has a scope. The scope "debian" is used for the default storage structure. On the next level the single data nodes are defined. I Some short description about the node and its data. I Organizational node under which the data is stored. struc_rdn + ou=CipUX + LDAP suffix. Example: ou=Task,ou=CipUX,dc=nodomain will gives us ou=Task as struc_rdn struc_rdn => 'ou=Task', I The first attribute of the dn line. This should correspond to the filter section. I This filter will be applied to get the data. =cut CipUX-Storage-3.4.0.2/lib/cipux-access.ini.pod0000444000175000017500000000365611237647212021100 0ustar ckuelkerckuelker =pod =head1 cipux-access.ini The CipUX Storage layer comes with two configuration files. One for configuring basic values. This called typically cipux-storage.perl. The other holds the access data for the storage backend. Mostly called cipux-access.ini. This document descibes cipux-access.ini. Example: [ldap] uri = ldap://localhost bind_dn = cn=cipuxroot,dc=example,dc=org base_dn = ou=CipUX,dc=example,dc=org password = secret system = debian customer = Configuration files may be provided for convenience. This is meant to work in a single-server scenario and multi-server settings. For this reason the configuration file is splitted into two files: one for credentials (access) and the other for the LDAP object/node types (structure). The idea is, that in a multi-server setting, the structure remain the same, whereas the credentials will change from server to server. The default behavior is to throw an exception, when some parameter value of the configuration file or passed parameter value is missing. Two different parameter value handlings exist: password and structure_cfg. Please read the appropriate sections for detailed information. I You have to specify an I, such as 'ldap://localhost' or 'ldaps://127.0.0.1:666' or 'ldapi://%2fvar%2flib%2fldap_sock'. Note that '%2f's in the LDAPI socket path will be translated into '/'. This is to support LDAP query options like base, search etc. although the query part of the URI will be ignored in this context. If port is not specified in the URI, the default is either 389 or 636 for 'LDAP' and 'LDAPS' schemes respectively. See Net::LDAP for details. I Example: bind_dn=>'cn=admin,dc=nodomain', I Example: base_dn=>'ou=CipUX,dc=nodomain', I Example: password=>'topsecret', I Not used at the moment. Example: system=>'debian', I Not used at the moment. Example: customer=>'Name of Institute', =cut CipUX-Storage-3.4.0.2/t/0000755000175000017500000000000011237647212014714 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/t/perlcriticrc0000444000175000017500000000101611237647212017320 0ustar ckuelkerckuelker# CipUX Perl::Critic Configuration # # SEVERITY NAME ...is equivalent to... SEVERITY NUMBER # ---------------------------------------------------- # gentle 5 # stern 4 # harsh 3 # cruel 2 # brutal 1 severity = stern verbose = 11 CipUX-Storage-3.4.0.2/t/perlcritic_cpan.t0000444000175000017500000000101011237647212020230 0ustar ckuelkerckuelker#!perl # use strict; use warnings; use File::Spec; use Test::More; use English qw(-no_match_vars); if ( not $ENV{TEST_AUTHOR} ) { my $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.'; plan( skip_all => $msg ); } eval { require Test::Perl::Critic; }; if ($EVAL_ERROR) { my $msg = 'Test::Perl::Critic required to criticise code'; plan( skip_all => $msg ); } my $rcfile = File::Spec->catfile( 't', 'perlcriticrc' ); Test::Perl::Critic->import( -profile => $rcfile ); all_critic_ok(); CipUX-Storage-3.4.0.2/t/leaktrace.t0000444000175000017500000000107511237647212017035 0ustar ckuelkerckuelkeruse Test::More tests => 1; use Test::LeakTrace; # TODO: if /var/cache/cipux is not there we would get a small memory leak (50) # because of 3rd party Perl modules in the second run however we should not get # any. Remove memory leaks from 3rd party modules and then remove this line. diag('CipUX::Storage _build/cache 1'); my $object1 = CipUX::Storage->new( { cache_dir => '_build/cache' } ); # 1 diag('CipUX::Storage _build/cache 2'); no_leaks_ok { use CipUX::Storage; my $object2 = CipUX::Storage->new( { cache_dir => '_build/cache' } ); } 'no memory leaks'; CipUX-Storage-3.4.0.2/t/00.load.t0000444000175000017500000000024411237647212016234 0ustar ckuelkerckuelkeruse Test::More tests => 2; BEGIN { use_ok('CipUX::Storage'); use_ok('CipUX::Storage::Client'); } diag("Testing CipUX::Storage $CipUX::Storage::VERSION"); CipUX-Storage-3.4.0.2/t/perlcritic.t0000444000175000017500000000043611237647212017242 0ustar ckuelkerckuelker#!perl use strict; use warnings; use Test::More; use English qw(-no_match_vars); eval { require Test::Perl::Critic; }; if ($EVAL_ERROR) { my $msg = 'Test::Perl::Critic required to for testing PBP compliance'; plan( skip_all => $msg ); } Test::Perl::Critic::all_critic_ok(); CipUX-Storage-3.4.0.2/t/pod-coverage.t0000444000175000017500000000026111237647212017451 0ustar ckuelkerckuelker#!perl -w use Test::More; eval "use Test::Pod::Coverage 1.04"; plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; all_pod_coverage_ok(); CipUX-Storage-3.4.0.2/t/pod.t0000444000175000017500000000021411237647212015656 0ustar ckuelkerckuelker#!perl -T use Test::More; eval "use Test::Pod 1.14"; plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; all_pod_files_ok(); CipUX-Storage-3.4.0.2/t/refcount.t0000444000175000017500000000133511237647212016726 0ustar ckuelkerckuelkeruse Test::More tests => 4; use Test::Refcount; use CipUX::Storage; # 1 diag('new CipUX::Storage _build/cache'); my $object1 = CipUX::Storage->new( { cache_dir => '_build/cache' } ); is_oneref( $object1, '$object has a refcount of 1' ); # 2 diag('refcount CipUX::Storage'); my $otherref1 = $object1; is_refcount( $object1, 2, '$object now has 2 references' ); use CipUX::Storage::Client; # 3 diag('new CipUX::Storage::Client'); my $object2 = CipUX::Storage::Client->new( { name => 'cipux_storage_client', cache_dir => '_build/cache' } ); is_oneref( $object2, '$object has a refcount of 1' ); # 4 diag('refcount CipUX::Storage::Client'); my $otherref2 = $object2; is_refcount( $object2, 2, '$object now has 2 references' ); CipUX-Storage-3.4.0.2/Changes0000444000175000017500000000320111237647212015736 0ustar ckuelkerckuelkerRevision history for CipUX-Storage 3.4.0.2 2009-08-10+00:30:12 - changes: * add dependency Test::LeakTrace * tighten dependency to CipUX 3.4.0.5 * change test cache dir from blib to _build - contributor: Christian Kuelker - version created by: Christian Kuelker 3.4.0.1 2009-08-09+01:46:28 - changes: * add refcount test * remove indirect build dependency Module::Build * add leaktrace.t test * Fix BUG - UID and GID in shares now counted correctly * add cache_dir parameter to test leaktrace and refcount * add cache_dir parameter to CipUX::Storage - contributor: * Christian Kuelker * Kurt Gramlich - version created by: Christian Kuelker 3.4.0.0 2009-03-14+22:14:45 - version created by: Christian Kuelker 3.4.0 2008-07-04+23:30:00 - Renamed to CipUX::Storage - version created by: Christian Kuelker 3.003099 2007-12-12+05:16:17 - CipUX:LDAP - version created by: Christian Kuelker 3.002016 2007-08-21+01:12:23 - version created by: Christian Kuelker 3.002015 Fri Jun 08 22:24:25 2007 - original version; created by h2xs 1.23 with options -v 3.002015 -XA -n LDAP CipUX-Storage-3.4.0.2/MANIFEST0000444000175000017500000000121411237647212015576 0ustar ckuelkerckuelkerbin/cipux_storage_client Build.PL Changes doc/debian-edu/cat.ldif doc/debian-edu/cipadmin-group.ldif doc/debian-edu/cipadmin-user.ldif doc/debian-edu/cipuxroot.ldif doc/debian-edu/extrastructs.patch doc/debian-edu/room.ldif doc/debian-edu/slapd_acl_cipuxroot.conf doc/debian-edu/task.ldif lib/cipux-access.ini.pod lib/cipux-storage.perl.pod lib/CipUX/Storage.pm lib/CipUX/Storage/Client.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP META.yml README t/00.load.t t/leaktrace.t t/perlcritic.t t/perlcritic_cpan.t t/perlcriticrc t/pod-coverage.t t/pod.t t/refcount.t usr/share/cipux/etc/cipux-access.ini usr/share/cipux/etc/cipux-storage.perl CipUX-Storage-3.4.0.2/bin/0000755000175000017500000000000011237647212015221 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/bin/cipux_storage_client0000555000175000017500000003517711237647212021374 0ustar ckuelkerckuelker#!/usr/bin/perl -w -T # +=======================================================================+ # || cipux_storage_client || # || || # || Command line interface for CipUX Storage abstraction layer. || # || || # || Copyright (C) 2008 - 2009 by Christian Kuelker. || # || || # || GNU GPL version 2 or any later version. || # || || # +=======================================================================+ # ID: $Id$ # Revision: $Revision$ # Head URL: $HeadURL$ # Date: $Date$ # Source: $Source$ package cipux_storage_client; ## no critic (Capitalization) use 5.008001; use strict; use warnings; use CipUX::Storage::Client; use version; our $VERSION = qv('3.4.0.2'); delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer # +=============================================================================+ # || MAIN || # +=============================================================================+ my $client = CipUX::Storage::Client->new( { name => 'cipux_storage_client' } ); $client->run(); exit 0; __END__ =pod =head1 NAME cipux_storage_client - Command line interface to CipUX storage abstraction layer =head1 VERSION version 3.4.0.2 =head1 USAGE (1) cipux_storage_client -h (2) cipux_storage_client [OPT] -t get_value -s -o -y [-y ] (3) cipux_storage_client [OPT] -t get_all_values -s -y [-y ] (4) cipux_storage_client [OPT] -t set_value [-r] -s -o -y -v cipux_storage_client [OPT] -t set_value -a -s -o -y -v cipux_storage_client [OPT] -t set_value [-r] -s -o -y [-y ] cipux_storage_client [OPT] -t set_value -a -s -o -y [-y ] cipux_storage_client [OPT] -t set_value -d -s -o -y [-y ] cipux_storage_client [OPT] -t set_value -e -s -o -y (5) cipux_storage_client [OPT] -t set_all_values [-r] -s -y -v cipux_storage_client [OPT] -t set_all_values -a -s -y -v cipux_storage_client [OPT] -t set_all_values [-r] -s -y [-y ] cipux_storage_client [OPT] -t set_all_values -a -s -y [-y ] cipux_storage_client [OPT] -t set_all_values -d -s -y [-y ] (6) cipux_storage_client [OPT] -t add_node -s -o -x [-x ] (7) cipux_storage_client [OPT] -t delete_node -s -o (8) cipux_storage_client [OPT] -t rename_node -s -o -v abbreviations: OBJ = OBJECT, ATTR = ATTRIBUTE, VAL = VALUE, OPT = OPTIONS =head1 OPTIONS Options for all commands: -c | --cfg : cipux-storage-access.conf -D | --debug [] : print debug messages for developers -h | --help : print help (this message + options) -p | --pretty : nice boxed output -V | --version : print only version --verbose : print more messages Options for some commands: -a | --add : rather add then replace a value -d | --del : delete the value of the attribute -e | --erase : delete the attribute -l | --list : lists configuration scopes, can be used for --type -o | --object : LDAP object leaf -r | --replace : replace a value, default behaviour -s | --storage_type : configuration type -t | --storage_task : action to perform -v | --value : value to be set -x | --mattrvalue : multiple LDAP attributes, please see description -y | --attrvalue : LDAP attribute, please see description =head1 REQUIRED ARGUMENTS cipux_storage_client -t or -h cipux_storage_client -t get_value -s -o -y cipux_storage_client -t get_all_values -s -y cipux_storage_client -t set_value -s -o -y cipux_storage_client -t set_all_values -s -y -v cipux_storage_client -t add_node -s -o -x cipux_storage_client -t delete_node -s -o cipux_storage_client -t rename_node -s -o -v =head1 DESCRIPTION OF OPTIONS =over 4 =item I<-a> Same as option --add. =item I<--add> This adds a value where possible rather then replace a value. =item I<--attrvalue> This can be used to specify the attribute by --attrvalue Or it can be used to specify the attribute and the value --attrvalue = Of course it can also be use together with --value option to specify the attribute and the value like this: --attrvalue --value =item I<-D> Same as option --debug. =item I<-d> Same as option --del. =item I<--del> This deletes the attribute from the object where possible. =item I<-e> Same as option --erase =item I<--erase> Deletes the LDAP attribute of a given object. This will delete also all content of this attribute. If the an object has multible values for that attribute all values will be removed. If this is option is set, it will trigger --delete command line option automatically. =item I<-h> Same as option --help =item I<--help> Prints brief help message. =item I<--mattrvalue> This is option have to be use if a LDAP object has to be created. Unlike --attrvalue this option requires always an attribute and a value. Therefore only this syntax is possible: --mattrvalue = The reason for this is to be able to gave the user exact hints when he try to create a object but forget the value. The 'm' stands for multiple. So it is possible to give the option several times. =item I<-o> Same as option --object =item I<--object> This option is used to specify the object on which the command is operating. Make sure you choose the right object. Of course this will also fail when the object is not fetchable with (in the objects list of) --storage_type. =item I<-p> Same as option --pretty. =item I<--pretty> On command which produce an output, this option can be used to draw a fancy box around the output. =item I<-r> Same as option --replace. =item I<--replace> For some command this is the default option. It replace the value of a given attribute with a new value. =item I<-s> Same as option --storage_type. =item I<--storage_task> Name fo the action that can be performed. Valid actions are: get_all_values set_all_values add_node get_value set_value list delete_node rename_node =item I<--storage_type> This option defines the 'type of the object' the command is operating with. A 'type of object' is a certain set of objects with common attributes. For example all POSIX account objects. You can easily define new types of objects in the configuration file. The default location of this file is /etc/cipux/cipux-storage-structure.conf. =item I<-t> Same as --storage_task. =item I<-V> Same as option --version. =item I<--version> Prints the version and exits. =item I<--verbose> Not implemented jet. =item I<-l> Same as option --list =item I<--list> Lists all object scopes. The object scopes are red from the configuration file. The default location of the configuration file is /usr/share/cipux/etc/cipux-storage.perl. One object type is needed for the --storage_type option. =item I<-v> Same as option --verbose. =item I<--value> On some commands this is use to provide a value for an object or an attribute. =item I<-x> Same as option --mattrvalue. =item I<-y> Same as option --attrvalue. =back =head1 DESCRIPTION This is the command line client for CipUX::Storage. It can be used to get modify or delete CipUX storage objects. =head1 COMMANDS cipux_storage_client -t get_value cipux_storage_client -t set_value cipux_storage_client -t get_all_values cipux_storage_client -t set_all_values cipux_storage_client -t add_node cipux_storage_client -t rename_node cipux_storage_client -t delete_node =head2 cipux_storage_client -t get_value Retrieve one or more LDAP values for every given attribute of a given object. =head2 cipux_storage_client -t get_all_values Retrieve one or more LDAP values for every given attribute of all objects in a given object type. =head2 cipux_storage_client -t set_value (1) You can add values with cipux_storage_client -t set_value. cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login -a But this make only a difference for LDAP attributes which can be there more then one time. cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login1 -a cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login2 -a This will result: memberUid: login1 memberUid: login2 Where as the following lines have a different result: cipux_storage_client -t set_value -s all_group_node -e groupType -o testgruppe -v public -a The resulting exception: attribute 'groupType' cannot have multiple values at ./cipux_storage_client -t set_value line 369 In this case you have to remove the -a option from your line or use -r. (2) The default behavior is to replace values. Values can be replaces with: cipux_storage_client -t set_value -s all_group_node -e groupType -o testgruppe -v private or cipux_storage_client -t set_value -s all_group_node -e groupType -o testgruppe -v private -r This will replace the existing value with the new one. But be aware (!), if you have 3 members in a group, for example: memberUid: login1 memberUid: login2 memberUid: login3 after command the command: cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login4 you will have only one member! memberUid: login4 Therefor the default behavior is to replace all but one value. The replace and not the add is the default behavior, because it there are more single attributes in LDAP and therefor the probability of failure will be less if replace is the default behavior. (3) Also LDAP attributes can be deleted. If you have 2 memberUid's for example the delete operation will led to an exception: modify/delete: memberUid: no such value at ./cipux_storage_client -t set_value line 369 So to delete all (!) member you have to do two LDAP operations: cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login -r cipux_storage_client -t set_value -s all_group_node -e memberUid -o testgroup -v login -d Where as the value from -v is not important. =head2 cipux_storage_client -t set_all_values Set all LDAP values of a given object and attribute. =head2 cipux_storage_client -t add_node Adds an LDAP node. =head3 SYNOPIS cipux_storage_client -t add_node -s -o -x = [-x = ...] =head3 Usage example cipux_storage_client -t add_node -s cipux_room -o test1 -x objectClass=room -x objectClass=cipuxRoom -x cn=test1 If you do not provide cn=NAME for example, you will get the following exception: EXCEPTION mandatory attr [cn] is missing! Please provide -x or --mattrvalue command line option! Example: -x cn= To add a user node (not a complete user account!) this will create a half user account named testuser: cipux_storage_client -t add_node -s cipux_account.user -o testuser -x cipuxFirstname=test -x cipuxLastname=user -x objectClass=cipuxAccount -x objectClass=posixAccount -x objectClass=shadowAccount -x uid=testuser -x cn=testuser -x cipuxCreationDate=2007-10-26 -x uidNumber=20000 -x gidNumber=20000 -x homeDirectory=/home/testuser -x objectClass=imapUser -x mailMessageStore=/tmp -D 129 Of course this is just an example. It is not a good idea to give /tmp as mail storage directory or use a static uidNumber. But this or a similar command can be user to test the LDAP layer. =head2 cipux_storage_client -t rename_node The rename command sets upon the Net::LDAP command modrdn. And due to the fact that simply rename a LDAP dn is not hole task of renaming an LDAP leaf the command can rename only certain LDAP objects. It can for example rename a cipuxConfiguration LDAP leaf. Before renaming it looks basically like this: dn: cn=testconfig,ou=Configuration,ou=CipUX,dc=nodomain cipuxVariable: testvalue cn: testconfig objectClass: top objectClass: cipuxConfiguration If you now issue the command: cipux_storage_client -t rename_node -s cipux_configuration -o testconfig -v myconfig You will get dn: cn=myconfig,ou=Configuration,ou=CipUX,dc=nodomain cipuxVariable: testvalue cn: testconfig cn: myconfig objectClass: top objectClass: cipuxConfiguration You noticed the 'cn' has doubled, since LDAP expect a corresponding 'cn' in this LDAP object? There for this configuration has now two names. It should be difficult to crate now a new 'testconfig'. You have to delete 'cn: testconfig' attribute and value before you can create a new 'testconfig'. Because this is rather confusing, you should avoid renaming where possible. Deleting an object and recreate it is a safer way. =head2 cipux_storage_client -t delete_node Deletes a given LDAP node. =head1 DIAGNOSTICS TODO =head1 EXIT STATUS TODO =head1 CONFIGURATION /usr/share/cipux/etc/cipux_storage.perl =head1 DEPENDENCIES CipUX::Storage::Client =head1 INCOMPATIBILITIES Not known. =head1 BUGS AND LIMITATIONS Not known. =head1 SEE ALSO See the CipUX webpage and the manual at L See the mailing list L =head1 AUTHOR Christian Kuelker Echristian.kuelker@cipworx.orgE =head1 LICENSE AND COPYRIGHT Copyright (C) 2008 - 2009 by Christian Kuelker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut CipUX-Storage-3.4.0.2/MANIFEST.SKIP0000444000175000017500000000022711237647212016346 0ustar ckuelkerckuelker-stamp$ \.orig$ \.bak$ \.swp$ \.svn _build blib Build$ \.ptkdb$ .deb$ .build$ .changes$ .upload$ .asc$ .dsc$ .tar.gz$ .cvsignore debian/files$ \..*\~$ CipUX-Storage-3.4.0.2/usr/0000755000175000017500000000000011237647212015262 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/usr/share/0000755000175000017500000000000011237647212016364 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/usr/share/cipux/0000755000175000017500000000000011237647212017514 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/usr/share/cipux/etc/0000755000175000017500000000000011237647212020267 5ustar ckuelkerckuelkerCipUX-Storage-3.4.0.2/usr/share/cipux/etc/cipux-access.ini0000444000175000017500000000042011237647212023351 0ustar ckuelkerckuelker # cipux-access.ini # You should copy this file to: /etc/cipux/cipux-access.ini # and edit it to your needs [ldap] uri = ldap://localhost bind_dn = cn=cipuxroot,dc=example,dc=org base_dn = ou=CipUX,dc=example,dc=org #password = secret system = debian customer = CipUX-Storage-3.4.0.2/usr/share/cipux/etc/cipux-storage.perl0000444000175000017500000002066511237647212023754 0ustar ckuelkerckuelker# +=========================================================================+ # || /usr/share/cipux/etc/cipux-storage.perl || # || || # || Bootstrap configuration file for the storage abstraction layer. It || # || should provide the structure off LDAP object/node types. || # || See manual page for more information. || # || || # || Copyright (C) 2007 - 2009 by Christian Kuelker || # || || # || License: GNU GPL version 2 or any later version. || # || || # +=========================================================================+ my $cfg = { 'structure' => { 'cipux_ldap_orga_node' => { desc => 'access all CipUX LDAP orga nodes', struc_rdn => '', dn_attr => 'ou', filter => '&(ou=?)(objectClass=cipuxLdapOrgaNode)', }, 'cipux_admin' => { desc => 'access all CipUX admin nodes', struc_rdn => '', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxAdmin)', }, 'cipux_configuration' => { desc => 'access all CipUX configuration nodes', struc_rdn => 'ou=Configuration', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxConfiguration)', }, 'cipux_task' => { desc => 'access all CipUX task nodes', struc_rdn => 'ou=Task', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxTask)', }, 'cipux_image' => { desc => 'access all CipUX image nodes', struc_rdn => 'ou=Image', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxImage)', }, 'cipux_client' => { desc => 'access all CipUX client nodes', struc_rdn => 'ou=Machine', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxMachine)', }, 'cipux_room' => { desc => 'access all CipUX room nodes', struc_rdn => 'ou=Room', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxRoom)', }, 'cipux_cat_module' => { desc => 'access all CipUX cat_module nodes', struc_rdn => 'ou=CAT', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxCatModule)', }, 'cipux_hardware_type' => { desc => 'access all CipUX hardware_type nodes', struc_rdn => 'ou=HardwareType', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxHardwareType)', }, 'cipux_image_slot' => { desc => 'access all CipUX image_slot nodes', struc_rdn => 'ou=ImageSlot', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxImageSlot)', }, 'cipux_account.user' => { desc => 'access all CipUX user account user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsAccount=TRUE)', }, 'cipux_account.group' => { desc => 'access all CipUX user account group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsAccount=TRUE)', }, 'authority_account.group' => { desc => 'access all CipUX entities in lisAcl auth groups', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(groupType=authority_group)', }, 'cipux_guest_account.user' => { desc => 'access all CipUX user guest_account user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsGuestAccount=TRUE)', }, 'cipux_guest_account.group' => { desc => 'access all CipUX user guest_account group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsGuestAccount=TRUE)', }, 'cipux_examinee_account.user' => { desc => 'access all CipUX user examinee_account user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsExamineeAccount=TRUE)', }, 'cipux_examinee_account.group' => { desc => 'access all CipUX user examinee_account group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsExamineeAccount=TRUE)', }, 'cipux_share.user' => { desc => 'access all CipUX user share user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsShare=TRUE)', }, 'cipux_share.group' => { desc => 'access all CipUX user share group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsShare=TRUE)', }, 'cipux_global_share.user' => { desc => 'access all CipUX user global_share user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsGlobalShare=TRUE)', }, 'cipux_global_share.group' => { desc => 'access all CipUX user global_share group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsGlobalShare=TRUE)', }, 'cipux_examination_share.user' => { desc => 'access all CipUX user examination_share user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsExaminationShare=TRUE)', }, 'cipux_examination_share.group' => { desc => 'access all CipUX user examination_share group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsExaminationShare=TRUE)', }, 'cipux_documenation_share.user' => { desc => 'access all CipUX user documenation_share user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsDocumentationShare=TRUE)', }, 'cipux_documenation_share.group' => { desc => 'access all CipUX user documenation_share group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsDocumentationShare=TRUE)', }, 'cipux_skel.user' => { desc => 'access all CipUX user skel user nodes', struc_rdn => 'ou=User', dn_attr => 'uid', filter => '&(uid=?)(objectClass=cipuxAccount)(cipuxIsSkel=TRUE)', }, 'cipux_skel.group' => { desc => 'access all CipUX user skel group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(objectClass=cipuxGroup)(cipuxIsSkel=TRUE)', }, 'cipux_role.group' => { desc => 'access all CipUX user role group nodes', struc_rdn => 'ou=Group', dn_attr => 'cn', filter => '&(cn=?)(groupType=authority_group)', }, 'cipux_netgroup' => { desc => 'access all Debian-Edu netgroup nodes', struc_rdn => 'ou=Netgroup', dn_attr => 'cn', filter => '&(cn=?)(objectClass=nisNetgroup)', }, }, }; return $cfg; CipUX-Storage-3.4.0.2/META.yml0000444000175000017500000000154711237647212015727 0ustar ckuelkerckuelker--- name: CipUX-Storage version: 3.4.0.2 author: - 'Christian Kuelker ' abstract: Storage abstraction layer for CipUX license: gpl resources: homepage: http://www.cipux.org license: ~ requires: Carp: 0 CipUX: 3.4.0.5 Class::Std: 0.0.9 Data::Dumper: 0 Getopt::Long: 0 Log::Log4perl: 0 Net::LDAP: 0 Pod::Usage: 0 Readonly: 0 version: 0 build_requires: Module::Build::CipUX: 0.3.0 Test::LeakTrace: 0 Test::More: 0 Test::Pod: 1.14 Test::Refcount: 0 recommends: Test::Perl::Critic: 0 Test::Pod::Coverage: 1.04 provides: CipUX::Storage: file: lib/CipUX/Storage.pm version: 3.4.0.2 CipUX::Storage::Client: file: lib/CipUX/Storage/Client.pm version: 3.4.0.2 generated_by: Module::Build version 0.32 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.2.html version: 1.2 CipUX-Storage-3.4.0.2/README0000444000175000017500000000106611237647212015332 0ustar ckuelkerckuelkerCipUX-Storage version 3.4.0.2 Storage Abstraction Layer. Storage low-level tools. INSTALLATION To install this module, preferably run the following commands: perl Build.PL ./Build ./Build test ./Build install DEPENDENCIES Carp Class::Std CipUX Data::Dumper English Getopt::Long Log::Log4perl Net::LDAP Pod::Usage Readonly utf8 version COPYRIGHT AND LICENCE Copyright (C) 2007 - 2009, Christian Kuelker This library is licensed under the GNU GPL (General Public License) version 2 or any later version. CipUX-Storage-3.4.0.2/Build.PL0000444000175000017500000000232611237647212015746 0ustar ckuelkerckuelkeruse strict; use warnings; use Module::Build::CipUX; my $builder = Module::Build::CipUX->new( module_name => 'CipUX::Storage', license => 'gpl', dist_author => 'Christian Kuelker ', dist_version_from => 'lib/CipUX/Storage.pm', # create_makefile_pl => 'traditional', # create_readme => 1, installdirs => 'vendor', meta_merge => { resources => { homepage => q(http://www.cipux.org), }, }, recommends => { 'Test::Perl::Critic' => 0, 'Test::Pod::Coverage' => '1.04', }, build_requires => { 'Module::Build::CipUX' => '0.3.0', 'Test::More' => 0, 'Test::Pod' => '1.14', 'Test::Refcount' => 0, 'Test::LeakTrace' => 0, }, requires => { 'Carp' => 0, 'Class::Std' => '0.0.9', 'CipUX' => '3.4.0.5', 'Data::Dumper' => 0, 'Getopt::Long' => 0, 'Log::Log4perl' => 0, 'Net::LDAP' => 0, 'Pod::Usage' => 0, 'Readonly' => 0, 'version' => 0, }, add_to_cleanup => ['CipUX-Storage-*'], ); $builder->create_build_script(); CipUX-Storage-3.4.0.2/Makefile.PL0000444000175000017500000000017111237647212016420 0ustar ckuelkerckuelkeruse Module::Build::Compat; Module::Build::Compat->run_build_pl(args => \@ARGV); Module::Build::Compat->write_makefile();