#!/usr/local/bin/perl # ###################################################################### ### ### ### CGI不正リンク防止&ダウンロード数集計 T-FileSafe Ver.1.00 ### [1/2] 本体 (tfsafe.cgi) ### (c) 1996-2002 Takahiro Nishida ### http://www.mytools.net/ ### ### ###################################################################### # ### 変数設定部 (詳細は上記ページをご覧下さい) ###################### # CGIデータ置き場 $basedir = "."; # ファイル置き場 $rootdir = "/tfsdata"; ### 変数設定部 (ここまで)########################################### # アクセス拒否時に詳細メッセージを表示するか $SHOW_DETAIL_MESSAGE = 0; # 時差の修正 $time_fix = 0; # エラーログの位置 $errorlog = "$basedir/errors.txt"; # アクセスログの位置 $accesslog = "$basedir/access.txt"; $configfile = "$rootdir/config.txt"; $verno = '1.00'; &main; sub main{ &get_variables; &check_path_info; &get_config; &check_host_addr; &check_host_name; &check_referer; &check_file_status; &putout_file; &record_access_log; } ########## 各種変数の取得 sub get_variables{ $referer = $ENV{'HTTP_REFERER'}; $host_addr = $ENV{'REMOTE_ADDR'}; $host_name = $ENV{'REMOTE_HOST'}; $path_info = $ENV{'PATH_INFO'}; ($host_addr) || ($host_addr = ":unknown:"); ($host_name) || ($host_name = ":unknown:"); ($referer) || ($referer = ":unknown:"); } ########## PATH_INFO の取得 sub check_path_info{ ($path_info) || &error("00"); ($path_info =~ /\.\./) && &error("01"); ($path_info =~ /%/) && &error("01"); ($path_info eq "/config.txt") && &error("01"); ($file_ext) = $path_info =~ m|\/.+\.(.+)$|ig; $file_ext = lc($file_ext); } ########## 設定ファイルの読込 sub get_config{ open(FILE, "$configfile") || die &error("99"); @configs = ; close(FILE); $target = ""; ### 対象の拡張子のデータのみ取り出す foreach(@configs){ (/^[#\n]/) && next; if(/^TARGET:(.+)/){ $extflag = 0; $tmpflag = 0; if($1 eq '*'){ $tmpflag = 1; } else{ $exts = " $1 "; ($exts =~ / $file_ext /i) && ($extflag = 1); } } else{ ($tmpflag) && unshift(@tmplists, $_); ($extflag) && unshift(@extlists, $_); } } ### 拡張子が見つからなかった場合は * が対象 (@extlists) || (@extlists = @tmplists); ### 旧式(0.01)のconfig.txt形式への対応 (@extlists) || (@extlists = @configs); ### 条件毎に分割 foreach(@extlists){ chop; (/^#/) && next; if(/^(.+)\s+from\s+(.+)\s+(.+)$/){ if($1 eq "deny"){ if($2 eq "ADDR"){ push(@addr_deny, $3); } elsif($2 eq "HOST"){ push(@host_deny, $3); } elsif($2 eq "URL"){ push(@url_deny, $3); } } elsif($1 eq "allow"){ if($2 eq "ADDR"){ push(@addr_allow, $3); } elsif($2 eq "HOST"){ push(@host_allow, $3); } elsif($2 eq "URL"){ push(@url_allow, $3); } } } } } ########## IPアドレスのチェック sub check_host_addr{ ### IP allow 判定 if(@addr_allow){ foreach(@addr_allow){ ($host_addr =~ /$_/) && return; } &error("11"); } ### IP deny 判定 foreach(@addr_deny){ ($host_addr =~ /$_/) && &error("12"); } } ########## ホスト名のチェック sub check_host_name{ ### HOST allow 判定 if(@host_allow){ foreach (@host_allow){ ($host_name =~ /$_/) && return; } &error("21"); } ### HOST deny 判定 foreach (@host_deny){ ($host_name =~ /$_/) && &error("22"); } } ########## リンク元URLのチェック sub check_referer{ ### URL allow 判定 if(@url_allow){ foreach(@url_allow){ ($referer =~ /$_/) && return; } &error("31"); } ### URL deny 判定 foreach(@url_deny){ ($referer =~ /$_/) && &error("32"); } } ########## ファイルステータス取得 sub check_file_status{ $server_path = "$rootdir/$path_info"; (-f $server_path) || &error("02"); ($file_size = -s $server_path) || &error("03"); @stats = stat($server_path); $last_modified = &get_time_GMT($stats[9]); } ########## MIMEヘッダの出力 sub set_mime_header{ &mime_header_list; $mime_header = $HEAD{$file_ext} || &error("05"); print "Content-Type: $mime_header\n"; print "Content-Length: $file_size\n"; print "Last-Modified: $last_modified\n"; print "\n"; } ########## ファイルの出力 sub putout_file{ $target_file = "$rootdir/$path_info"; $| = 1; open(FILE, "$target_file") || die &error("04"); &set_mime_header; binmode(FILE); while(read(FILE, $buf, 16384)){ print $buf; } close(FILE); } ########## エラーメッセージの表示 sub error{ local($id) = @_; $time_now = &get_time; # エラーログの記録 if(-f $errorlog){ ($host_name eq ":unknown:") && ($host_name = $host_addr); open(FILE, ">>$errorlog") || die $!; print FILE "[$time_now] ERROR $id ($path_info) Host:$host_name Ref:$referer\n"; close(FILE); } ### エラーコード一覧 $ES{'00'} = "no filename"; $ES{'01'} = "invalid character in filepath"; $ES{'02'} = "file not found"; $ES{'03'} = "file contains no data"; $ES{'04'} = "cannot open file"; $ES{'05'} = "unknown file type"; $ES{'11'} = "IP not allowed"; $ES{'12'} = "denied by IP"; $ES{'21'} = "HOST not allowed"; $ES{'22'} = "denied by HOST"; $ES{'31'} = "URL not allowed"; $ES{'32'} = "denied by URL"; $ES{'99'} = "cannot open configfile"; ($SHOW_DETAIL_MESSAGE) && ($msg = " - $ES{$id}"); print "Content-type: text/html\n\n"; print "Access Denied.\n"; print "

Access Denied.

\n"; print "Your access to file \"$path_info\" has been denied, sorry.

\n"; print "(Error Code: $id $msg)


\n"; print "\n"; print "Powered by T-FileSafe Ver.$verno\n"; print ""; exit; } ########## アクセスログの記録 sub record_access_log{ (-f $accesslog) || return; $time_now = &get_time; ($host_name eq ":unknown:") && ($host_name = $host_addr); open(FILE, ">>$accesslog") || die $!; print FILE "[$time_now] GET ($path_info) Host:$host_name, Ref:$referer\n"; close(FILE); } ########## 現在時刻の取得 sub get_time{ $tsec = time() + 60 * 60 * $time_fix; local($sec, $min, $hour, $mday, $mon, $year) = localtime($tsec); $mon++; $year += 1900; return sprintf("%04d/%02d/%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec); } ##### GMTを得る sub get_time_GMT{ local($tsec) = @_; local($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($tsec); $wday = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')[$wday]; $mon = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')[$mon]; $year += 1900; return sprintf("$wday, %02d $mon $year %02d:%02d:%02d GMT", $mday, $hour, $min, $sec); } ############################################ # MIME-TYPE の追加 # 書式:$HEAD{'<拡張子>'} = ; ############################################ sub mime_header_list{ $HEAD{'txt'} = "text/plain"; $HEAD{'html'} = "text/html"; $HEAD{'htm'} = "text/html"; $HEAD{'mid'} = "audio/midi"; $HEAD{'jpg'} = "image/jpeg"; $HEAD{'gif'} = "image/gif"; $HEAD{'png'} = "image/png"; $HEAD{'lzh'} = "application/octet-stream"; $HEAD{'zip'} = "application/zip"; $HEAD{'mp3'} = "audio/mpeg"; $HEAD{'mmf'} = "application/x-smaf"; }