--- loncom/auth/lonwebdavacc.pm 2012/02/27 03:06:33 1.1 +++ loncom/auth/lonwebdavacc.pm 2014/06/23 20:27:46 1.2 @@ -1,7 +1,7 @@ # The LearningOnline Network # Authorization Handler for webDAV access to Authoring Space. # -# $Id: lonwebdavacc.pm,v 1.1 2012/02/27 03:06:33 raeburn Exp $ +# $Id: lonwebdavacc.pm,v 1.2 2014/06/23 20:27:46 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -124,6 +124,7 @@ use strict; use GDBM_File; use Apache::Constants qw(:common :http :methods); use Apache::lonnet; +use Apache::londiff(); use LONCAPA qw(:DEFAULT :match); sub handler { @@ -156,19 +157,62 @@ sub handler { } elsif (!-d "$docroot/priv/$adom/$aname") { return FORBIDDEN; } - # FIXME method check for MKCOL MOVE PUT DELETE for *.log, *.bak - # FIXME method check for regexp for "version-style" names: /\.\d+\.\w+$/ - # for MOVE PUT MKCOL + my $allowed; if (($env{'user.name'} eq $aname) && ($env{'user.domain'} eq $adom)) { if ($env{"user.role.au./$adom/"}) { - return OK; + $allowed = 1; } } else { if (($env{"user.role.ca./$adom/$aname"}) || (env{"user.role.aa./$adom/$aname"})) { - return OK; + $allowed = 1; } } + if ($allowed) { + my $method = $r->method(); + if (($r->filename =~ /.+\.(log|bak|meta|save)$/) || ($r->filename =~ /\.\d+\.\w+$/) || + ($r->filename =~ m{/\.+[^_/]+$})) { + if (($method eq 'MKCOL') || ($method eq 'PUT')) { + return FORBIDDEN; + } elsif ($method eq 'MOVE') { + if (($r->filename =~ /\.\d+\.\w+$/) || ($r->filename =~ m{/\.+[^_/]+$})) { + return FORBIDDEN; + } + } + } + if (($method eq 'DELETE') || ($method eq 'MOVE')) { + unless (($r->filename =~ m{/\._[^/]+$}) || ($r->filename =~ m{/\.DS_Store$})) { + my $dirptr=16384; + my ($cmode,$cmtime)=(stat($r->filename))[2,9]; + if (($cmode&$dirptr)) { + my $numpub = 0; + $numpub = &recurse_dir($r->filename,$r->dir_config('lonDocRoot'),$numpub); + if ($numpub) { + return FORBIDDEN; + } + } else { + if ($r->filename =~ /^(.+)\.(log|bak|save|meta)$/) { + my $conjugate = $1; + my $type = $2; + if (($type eq 'log') || ($type eq 'meta')) { + if (-e $conjugate) { + my $conjstatus = &pubstatus($conjugate,$r->dir_config('lonDocRoot')); + unless (($conjstatus eq 'unpublished') || ($conjstatus eq 'obsolete')) { + return FORBIDDEN; + } + } + } + } else { + my $status = &pubstatus($r->filename,$r->dir_config('lonDocRoot')); + unless (($status eq 'unpublished') || ($status eq 'obsolete')) { + return FORBIDDEN; + } + } + } + } + } + return OK; + } return FORBIDDEN; } @@ -201,4 +245,56 @@ sub sso_login { return ($handle); } +sub pubstatus { + my ($fn,$docroot,$cmtime) = @_; + my $privfn = $fn; + my $thisdisfn = $fn; + $thisdisfn=~s/^\Q$docroot\E\/priv//; + my $resfn=$docroot.'/res'.$thisdisfn; + my $targetfn = '/res'.$thisdisfn; + my $status = 'unpublished'; + if (-e $resfn) { + $status = 'published'; + my $same = 0; + if ((stat($resfn))[9] >= $cmtime) { + $same = 1; + } else { + if (&Apache::londiff::are_different_files($resfn,$privfn)) { + $same = 0; + } else { + $same = 1; + } + } + if ($same) { + if (&Apache::lonnet::metadata($targetfn,'obsolete')) { + $status = 'obsolete'; + } + } + } + return $status; +} + +sub recurse_dir { + my ($dirname,$docroot,$numpub) = @_; + $dirname =~ s{/$}{}; + my $dirptr=16384; + if (opendir(my $dirh,$dirname)) { + my @items = readdir($dirh); + closedir($dirh); + foreach my $item (@items) { + next if ($item =~ /.+\.(log|bak|save|meta)$/); + next if ($item =~ /^\.+/); + my ($cmode,$cmtime)=(stat("$dirname/$item"))[2,9]; + if (!($cmode&$dirptr)) { + if (&pubstatus("$dirname/$item",$docroot,$cmtime) eq 'published') { + $numpub ++; + } + } else { + $numpub = &recursedir("$dirname/$item",$docroot,$numpub); + } + } + } + return $numpub; +} + 1;