diff -Nur smeserver-shared-folders-0.1/createlinks smeserver-shared-folders-0.1_encfs/createlinks --- smeserver-shared-folders-0.1/createlinks 2011-05-06 10:47:47.000000000 +0200 +++ smeserver-shared-folders-0.1_encfs/createlinks 2011-05-06 15:11:02.000000000 +0200 @@ -8,6 +8,7 @@ my $panel = "manager"; panel_link("shares", $panel); +panel_link("userpanel-encfs", $panel); #-------------------------------------------------- # actions for group-delete event diff -Nur smeserver-shared-folders-0.1/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/shares smeserver-shared-folders-0.1_encfs/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/shares --- smeserver-shared-folders-0.1/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/shares 2011-05-06 10:47:47.000000000 +0200 +++ smeserver-shared-folders-0.1_encfs/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/shares 2011-05-06 16:23:05.000000000 +0200 @@ -411,4 +411,75 @@ Permissions on this shared folder are managed manually, modifications will only affect web access if a password is required.

]]> + + + DESC_ENCRYPTION + + The followings options let you protect your data. If encryption is enabled, the data will never be stored in clear text on the server. Your share will either be "available" (data will appear as clear text, encryption/decryption is done on the fly), or protected (only the ciphered data is available on the server). Encryption can only be set at shared folder creation time. Also, read only groups are not supported with encrypted shared folders. If you enable encryption, only members of groups with read/write privileges will be able to access this share. + + + + + LABEL_ENCRYPTION + + Encryption + + + + + DESC_PASSWORD + + You need to choose a password to protect your data. This password must be at least 8 characters long. Do not loose this password. If you forget it, your data will be lost because there's no way to recover it. + + + + + LABEL_PASSWORD + + Password + + + + + LABEL_PASSWORD2 + + Password (confirmation) + + + + + DESC_INACTIVITY + + To provide additionnal security, you can set an inactivity time out (in minutes). When the data is available, if nobody access it for this period of time, the data will go back to protected mode automatically. + + + + + ERROR_WITH_ENCRYPTION + + An error occured while performing initial folder encryption + + + + + INVALID_INACTIVITY + + Inactivity value must be numbers only + + + + + PASSWORD_MISMATCH + + Passwords don't match + + + + + PASSWORD_TOO_SHORT + + Password is too short, please use at least 8 characters + + + diff -Nur smeserver-shared-folders-0.1/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/userpanel-encfs smeserver-shared-folders-0.1_encfs/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/userpanel-encfs --- smeserver-shared-folders-0.1/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/userpanel-encfs 1970-01-01 01:00:00.000000000 +0100 +++ smeserver-shared-folders-0.1_encfs/root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/userpanel-encfs 2011-05-06 15:34:51.000000000 +0200 @@ -0,0 +1,58 @@ + + + FORM_TITLE + Shared Folders Encryption + + + Shared Folders Encryption + Shared Folders Encryption + + + FIRSTPAGE_DESC + This panel lets you enable enrypted shared folder access. + + + STATUS + Status + + + MOUNTED + Enabled + + + NOT_MOUNTED + Protected + + + MOUNT + Enable + + + UMOUNT + Protect + + + ERROR_MOUNTING + An error occured. Check that you have the correct password. + + + UMOUNT_DESC + Are you sure you want to protect this shared folder ? Once protected, the content won't be accessible until re-enabled with the associated password. + + + MOUNT_DESC + You have to enter the password to make this folder's content available. + + + LABEL_MOUNT_PASSWORD + Password + + + VALIDATE + Validate + + + NO_ENCRYPTED_SHARE + No encrypted share configured + + diff -Nur smeserver-shared-folders-0.1/root/etc/e-smith/web/functions/shares smeserver-shared-folders-0.1_encfs/root/etc/e-smith/web/functions/shares --- smeserver-shared-folders-0.1/root/etc/e-smith/web/functions/shares 2011-05-06 10:47:47.000000000 +0200 +++ smeserver-shared-folders-0.1_encfs/root/etc/e-smith/web/functions/shares 2011-05-06 15:26:27.000000000 +0200 @@ -4,9 +4,10 @@ #---------------------------------------------------------------------- # heading : Collaboration # description : Shared Folders -# navigation : 2000 2500 +# navigation : 2000 2600 # -# Copyright (c) 2001 Mitel Networks Corporation +# Copyright (c) 2009 - 2011 Firewall-Services +# daniel@firewall-services.com # # 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 @@ -22,8 +23,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -# Technical support for this program is available from e-smith, inc. -# Please visit our web site www.e-smith.com for details. #---------------------------------------------------------------------- use strict; @@ -118,6 +117,15 @@ + + + + + DESC_INACTIVITY + + + + diff -Nur smeserver-shared-folders-0.1/root/etc/e-smith/web/functions/userpanel-encfs smeserver-shared-folders-0.1_encfs/root/etc/e-smith/web/functions/userpanel-encfs --- smeserver-shared-folders-0.1/root/etc/e-smith/web/functions/userpanel-encfs 1970-01-01 01:00:00.000000000 +0100 +++ smeserver-shared-folders-0.1_encfs/root/etc/e-smith/web/functions/userpanel-encfs 2011-05-06 15:26:45.000000000 +0200 @@ -0,0 +1,56 @@ +#!/usr/bin/perl -wT + +# vim: ft=xml ts=4 sw=4 et: +#---------------------------------------------------------------------- +# heading : Collaboration +# description : Shared Folders Encryption +# navigation : 2000 2700 +# +# Copyright (c) 2011 Firewall-Services +# daniel@firewall-services.com +# +# 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 of the License, 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 +# +#---------------------------------------------------------------------- + +use strict; +use esmith::FormMagick::Panel::userpanelEncfs; + +my $fm = esmith::FormMagick::Panel::userpanelEncfs->new(); +$fm->display(); + +__DATA__ +
+ + FIRSTPAGE_DESC + + + + MOUNT_DESC + + + + + + + UMOUNT_DESC + + +
+ + diff -Nur smeserver-shared-folders-0.1/root/etc/sysconfig/modules/fuse.modules smeserver-shared-folders-0.1_encfs/root/etc/sysconfig/modules/fuse.modules --- smeserver-shared-folders-0.1/root/etc/sysconfig/modules/fuse.modules 1970-01-01 01:00:00.000000000 +0100 +++ smeserver-shared-folders-0.1_encfs/root/etc/sysconfig/modules/fuse.modules 2011-05-06 15:28:48.000000000 +0200 @@ -0,0 +1,2 @@ +#!/bin/sh +modprobe fuse > /dev/null 2>&1 diff -Nur smeserver-shared-folders-0.1/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/shares.pm smeserver-shared-folders-0.1_encfs/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/shares.pm --- smeserver-shared-folders-0.1/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/shares.pm 2011-05-06 10:47:47.000000000 +0200 +++ smeserver-shared-folders-0.1_encfs/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/shares.pm 2011-05-06 16:33:09.000000000 +0200 @@ -14,6 +14,7 @@ use esmith::DomainsDB; use esmith::cgi; use esmith::util; +use File::Path; use File::Basename; use Exporter; use Carp; @@ -23,6 +24,7 @@ our @EXPORT = qw( print_share_table print_share_name_field + print_encryption_fields genGroupAccess smbAccess_list httpAccess_list @@ -175,6 +177,8 @@ # Set default value my $q = $self->{cgi}; + $q->param(-name=>'encryption',-value=>'disabled'); + $q->param(-name=>'inactivity',-value=>'30'); $q->param(-name=>'smbaccess',-value=>'browseable'); $q->param(-name=>'recyclebin',-value=>'disabled'); $q->param(-name=>'retention',-value=>'unlimited'); @@ -204,6 +208,10 @@ { $q->param(-name=>'description',-value=> $rec->prop('Name')); + $q->param(-name=>'encryption',-value=> + ($rec->prop('Encryption') || 'disabled')); + $q->param(-name=>'inactivity',-value=> + ($rec->prop('InactivityTimeOut') || '30')); $q->param(-name=>'ReadGroups',-value=> $rec->prop('ReadGroups')); $q->param(-name=>'WriteGroups',-value=> @@ -242,12 +250,55 @@ } +sub print_encryption_fields { + my $self = shift; + my $encryption = $self->{cgi}->param('encryption') || 'disabled'; + my $action = $self->{cgi}->param('action') || ''; + + print qq() . $self->localise('DESC_ENCRYPTION') . qq(); + print qq() . + $self->localise('LABEL_ENCRYPTION') . qq(\n); + + if ($action eq 'modify') { + print qq( + $encryption + + + ); + } + else { + print qq( + + ); + print qq() . $self->localise('DESC_PASSWORD') . qq(); + print qq() . + $self->localise('LABEL_PASSWORD') . qq(\n); + print qq( + + + ); + print qq() . + $self->localise('LABEL_PASSWORD2') . qq(\n); + print qq( + + + ); + } + + print qq(\n); + + return undef; +} + # Takes a comma delimited list of groups and returns a string of # html checkboxes for all system groups with the groups having write and read access. sub genGroupAccess () { my $fm = shift; - my $q = $fm->{'cgi'}; + my $q = $fm->{cgi}; my $WriteGroups = $q->param('WriteGroups') || ''; my $ReadGroups = $q->param('ReadGroups') || ''; my $share = $q->param('share'); @@ -426,6 +477,9 @@ sub create_share { my ($self) = @_; my $name = $self->cgi->param('name'); + my $encryption = $self->cgi->param('encryption') || 'disabled'; + my $password = $self->cgi->param('password'); + my $password2 = $self->cgi->param('password2'); my $msg = $self->validate_name($name); unless ($msg eq "OK") @@ -445,39 +499,66 @@ return $self->error($msg); } + $msg = $self->confirm_password($password,$password2); + unless ($msg eq "OK") + { + return $self->error($msg); + } + my @WriteGroups = $self->cgi->param('write'); my $WriteGroups = join(",",@WriteGroups); my @ReadGroups = $self->cgi->param('read'); my @CleanReadGroups = (); - # Remove from ReadGroups the groups in WriteGroups - # So ACL are consistent - foreach my $read (@ReadGroups){ - my $isInWrite = 0; - foreach (@WriteGroups){ - $isInWrite = 1 if ($_ eq $read); + # EncFS doesn't expose underlying ACLs + # So, just remove any read only groups + # Read Only is not supported with encryption + if ($encryption ne 'enabled'){ + # Remove from ReadGroups the groups in WriteGroups + # So ACL are consistent + foreach my $read (@ReadGroups){ + my $isInWrite = 0; + foreach (@WriteGroups){ + $isInWrite = 1 if ($_ eq $read); + } + push (@CleanReadGroups, $read) unless ($isInWrite); } - push (@CleanReadGroups, $read) unless ($isInWrite); } my $ReadGroups = join(",",@CleanReadGroups); if (my $acct = $accountdb->new_record($name, { - Name => $self->cgi->param('description'), - WriteGroups => $WriteGroups, - ReadGroups => $ReadGroups, - RecycleBin => $self->cgi->param('recyclebin'), - RecycleBinRetention => $self->cgi->param('retention'), - smbAccess => $self->cgi->param('smbaccess'), - httpAccess => $self->cgi->param('httpaccess'), - WebDav => $self->cgi->param('webdav'), - RequireSSL => $self->cgi->param('requireSSL'), - Indexes => $self->cgi->param('indexes'), - DynamicContent => $self->cgi->param('dynamic'), - type => 'share', + Name => $self->cgi->param('description'), + Encryption => $self->cgi->param('encryption'), + InactivityTimeOut => $self->cgi->param('inactivity'), + WriteGroups => $WriteGroups, + ReadGroups => $ReadGroups, + RecycleBin => $self->cgi->param('recyclebin'), + RecycleBinRetention => $self->cgi->param('retention'), + smbAccess => $self->cgi->param('smbaccess'), + httpAccess => $self->cgi->param('httpaccess'), + WebDav => $self->cgi->param('webdav'), + RequireSSL => $self->cgi->param('requireSSL'), + Indexes => $self->cgi->param('indexes'), + DynamicContent => $self->cgi->param('dynamic'), + type => 'share', }) ) { # Untaint $name before use in system() $name =~ /(.+)/; $name = $1; + + if ($encryption eq 'enabled'){ + my $source = '/home/e-smith/files/shares/' . $name . '/.store'; + my $dest = '/home/e-smith/files/shares/' . $name . '/files'; + File::Path::mkpath ($source); + mkdir $dest; + open(DIR, "| /usr/bin/encfs -S --public -o nonempty,umask=000 $source $dest > /dev/null 2>&1"); + print DIR "\n$password"; + close DIR; + $self->error("ERROR_WITH_ENCRYPTION") unless( + system("/bin/fusermount -uz $dest") == 0 + ); + } + if (system ("/sbin/e-smith/signal-event", "share-create", $name) == 0) { $self->success("SUCCESSFULLY_CREATED_SHARE"); } else { @@ -497,21 +578,29 @@ my $name = $self->cgi->param('name'); if (my $acct = $accountdb->get($name)) { if ($acct->prop('type') eq 'share') { + my $encryption = $self->cgi->param('encryption'); my @WriteGroups = $self->cgi->param('write'); my $WriteGroups = join(",",@WriteGroups); my @ReadGroups = $self->cgi->param('read'); my @CleanReadGroups = (); - foreach my $read (@ReadGroups){ - my $isInWrite = 0; - foreach (@WriteGroups){ - $isInWrite = 1 if ($_ eq $read); + + # EncFS doesn't expose underlying ACLs + # So, just remove any read only groups + # Read Only is not supported with encryption + if ($encryption ne 'enabled'){ + foreach my $read (@ReadGroups){ + my $isInWrite = 0; + foreach (@WriteGroups){ + $isInWrite = 1 if ($_ eq $read); + } + push (@CleanReadGroups, $read) unless ($isInWrite); } - push (@CleanReadGroups, $read) unless ($isInWrite); } my $ReadGroups = join(",",@CleanReadGroups); $acct->merge_props( Name => $self->cgi->param('description'), + InactivityTimeOut => $self->cgi->param('inactivity'), WriteGroups => $WriteGroups, ReadGroups => $ReadGroups, RecycleBin => $self->cgi->param('recyclebin'), @@ -592,5 +681,37 @@ return "OK"; } +# Check if inactivity is a number + +sub validate_inactivity +{ + my ($self, $inac) = @_; + + unless ($inac =~ /^\d+$/) + { + return $self->localise('INVALID_INACTIVITY', + {inactivity => $inac}); + } + return "OK"; +} + +# Check if both passwords match +# and are more than 8 chars + +sub confirm_password +{ + + my ($self, $pass1, $pass2) = @_; + + unless (scalar (split("",$pass1)) >= 8){ + return $self->localise('PASSWORD_TOO_SHORT'); + } + + unless ($pass1 eq $pass2){ + return $self->localise('PASSWORD_MISMATCH'); + } + return 'OK'; +} + 1; diff -Nur smeserver-shared-folders-0.1/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/userpanelEncfs.pm smeserver-shared-folders-0.1_encfs/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/userpanelEncfs.pm --- smeserver-shared-folders-0.1/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/userpanelEncfs.pm 1970-01-01 01:00:00.000000000 +0100 +++ smeserver-shared-folders-0.1_encfs/root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/userpanelEncfs.pm 2011-05-06 15:27:49.000000000 +0200 @@ -0,0 +1,145 @@ +#!/usr/bin/perl -w + +package esmith::FormMagick::Panel::userpanelEncfs; + +use strict; + +use esmith::FormMagick; +use esmith::AccountsDB; +use esmith::ConfigDB; +use esmith::cgi; +use esmith::util; +use File::Basename; +use Exporter; +use Carp; + +our @ISA = qw(esmith::FormMagick Exporter); + +our @EXPORT = qw( + print_share_table + mount_encfs + umount_encfs +); + +our $accountdb = esmith::AccountsDB->open(); +our $user = $ENV{'REMOTE_USER'}; +$user = $1 if ($user =~ /^([a-z][\-a-z0-9]*)$/); + +*wherenext = \&CGI::FormMagick::wherenext; + +sub new +{ + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = esmith::FormMagick::new($class); + $self->{calling_package} = (caller)[0]; + + return $self; +} + +sub print_share_table { + my $self = shift; + my $q = $self->{cgi}; + my @shares = $accountdb->get_all_by_prop(type => 'share'); + my @encfs = (); + + foreach (@shares){ + my @sharegroups = $_->prop('WriteGroups'), $_->prop('ReadGroups'); + @sharegroups = keys %{{ map { $_ => 1 } @sharegroups }}; + my @usergroups = $accountdb->user_group_list($user); + + my %count = (); + my @intersection = (); + foreach my $element (@sharegroups, @usergroups) { $count{$element}++ } + foreach my $element (keys %count) { + push @intersection, $element if ($count{$element} > 1); + } + + # Only display the share in the list if encryption is enabled + # and the user has at least read access + if ((($_->prop('Encryption') || 'disabled') eq 'enabled') && + ((scalar @intersection > 0 ) || $user eq 'admin')){ + push @encfs, $_ if (($_->prop('Encryption') || 'disabled') eq 'enabled'); + } + } + unless ( scalar @encfs ) + { + print $q->Tr($q->td($self->localise('NO_ENCRYPTED_SHARE'))); + return ""; + } + + print $q->start_table({-CLASS => "sme-border"}),"\n"; + print $q->Tr ( + esmith::cgi::genSmallCell($q, $self->localise('NAME'),"header"), + esmith::cgi::genSmallCell($q, $self->localise('DESCRIPTION'),"header"), + esmith::cgi::genSmallCell($q, $self->localise('STATUS'),"header"), + esmith::cgi::genSmallCell($q, $self->localise('ACTION'),"header", 3) + ),"\n"; + + my $scriptname = basename($0); + + foreach my $i (@encfs) + { + my $sharename = $i->key(); + my $sharedesc = $i->prop('Name'); + + my $mountstatus = `/bin/mount | /bin/grep /home/e-smith/files/shares/$sharename | grep -c fuse`; + chomp($mountstatus); + my $sharestatus = ($mountstatus eq '1') ? $self->localise('MOUNTED') : $self->localise('NOT_MOUNTED'); + + my $href = "$scriptname?page=;page_stack=;wherenext="; + + my $actionMount = $q->a({href => "${href}Mount&name=$sharename"},$self->localise('MOUNT')) + . ' '; + + my $actionUmount .= $q->a({href => "${href}Umount&name=$sharename"}, $self->localise('UMOUNT')) + . ' '; + + my $action = ($mountstatus eq '1') ? $actionUmount : $actionMount; + + print $q->Tr ( + esmith::cgi::genSmallCell($q, $sharename,"normal"), + esmith::cgi::genSmallCell($q, $sharedesc,"normal"), + esmith::cgi::genSmallCell($q, $sharestatus,"normal"), + esmith::cgi::genSmallCell($q, $action,"normal") + ); + } + + print $q->end_table,"\n"; + + return ""; +} + +sub mount_encfs { + my $fm = shift; + my $pass = $fm->{cgi}->param('password'); + my $share = $fm->{cgi}->param('name'); + my $rec = $accountdb->get($share); + my $timeout = $rec->prop('InactivityTimeOut') || '30'; + $timeout = '30' unless ($timeout =~ m/\d+/); + my $source = "/home/e-smith/files/shares/$share/.store"; + my $dest = "/home/e-smith/files/shares/$share/files"; + $pass = $1 if ( $pass =~ /(.*)/ ); + + unless ( system("echo $pass | /usr/bin/encfs -i $timeout -S --public -o nonempty,umask=000 $source $dest > /dev/null 2>&1") == 0){ + $fm->error('ERROR_MOUNTING'); + return undef; + } + + $fm->success('SUCCESS'); +} + +sub umount_encfs { + my $fm = shift; + my $share = $fm->{cgi}->param('name'); + + unless ( system("/bin/fusermount -uz /home/e-smith/files/shares/$share/files > /dev/null 2>&1") == 0){ + $fm->error('ERROR_UMOUNTING'); + return undef; + } + + $fm->success('SUCCESS'); +} + +1; +