#! /usr/local/bin/perl # ↑この上のPerlのパスを書き換えるのはお約束ですね #========================================================================================== # # マルチボード掲示板システム 『MultiBBS』ver 1.3 : メッセージ削除スクリプト # # Copyright Shinobu Suzuki 1998. All rights reserved. #----------------------------------------------------------------------------------------- # HomePage : http://www.aikis.or.jp/~s-suzuki/cgilabo/ # E-mail : s-suzuki@aikis.or.jp # Version : 1.32 # Update : 1999/02/27 #----------------------------------------------------------------------------------------- # ■MultiBBSシステムの指定されたボードのメッセージを削除します # ■入力されたパスワードをもとにモードの判定をします # ■管理者やボード主催者はすべてのメッセージを削除できます # ■ユーザーは自分の設定したパスワードに合致するメッセージだけを削除できます # ■簡単なドメイン別のアクセス制限(プロキシ制限等)ができます # **** # ■このスクリプトは config.cgi を参照しています # ■このファイルを設置しなければ、MultiBBSのメニューには表示されません #========================================================================================== # 初期設定 #----------------------------------------------------------------------------------------- # CERN HTTPDなどのサーバーの場合で、ファイル関係のエラーが # 出る場合、設置するディレクトリのフルパスを指定してみて下 # さい。なお、最後は / で終わること。 # 例) $path = "/home/users/s-suzuki/public_html/bbs/"; #---------------------------------------------------------- $path = ""; #---------------------------------------------------------- # 共通設定ファイルの指定 #---------------------------------------------------------- require "$path"."config.cgi"; #---------------------------------------------------------- # 外部からの(イタズラ)書き込みを禁止する場合、以下に、ス # クリプトのURLを記入する。(サーバーやブラウザによっては # うまくいかないこともあります) # 例:$script_url = 'http://www.aikis.or.jp/~s-suzuki/multibbs/remove.cgi'; #---------------------------------------------------------- $script_url = ''; #---------------------------------------------------------- # 書き込みの後のリロードに失敗する場合(File Not Foundので # る場合)、CGIスクリプトを設置するディレクトリ名をURLで指 # 定すると成功する場合があるそうです。 # ※この機能については未確認です # ※biglobeでは成功するそうです # ※v1.24より記述方法を変更しています # ※最後は / で終わること。 # 例:$rerload_url = 'http://www.aikis.or.jp/~s-suzuki/multibbs/'; #---------------------------------------------------------- $reload_url = ''; #===================================================================== # これより、処理の開始 #===================================================================== $| = 1; # ファイルバッファリングをしない &form; # フォーム入力された値の分解 &read_master_key; # 管理用マスターキー読み込み &read_domainlist; # 制限するドメインリストの読み込み &init; # 各種データ変数の初期化 &read_cfg; # ボード定義ファイルの読み込み #---------------------------------------------------------- # スクリプトの動作を決定($FORM{'task'}で判定) #---------------------------------------------------------- if ( $FORM{'task'} eq 'list' ) { # 編集データのリスト表示 &removelist; } elsif ( $FORM{'task'} eq 'remove') { # 編集画面 &remove_data; } else { &main; exit; } #===================================================================== # 処理はここまで(以下は、サブルーチン) #===================================================================== #---------------------------------------------------------------------- # 通常の画面表示ルーチン #---------------------------------------------------------------------- #----------------------------------------------------------------- # メイン画面 #----------------------------------------------------------------- sub main { if ($maintenance ne 0 ) { &error("ただ今、メンテナンス中です。"); } &html_header("MultiBBS:メッセージの削除"); print "
\n"; print "
削除するメッセージのパスワードか、管理用パスワードを入力して下さい。


\n"; print "
\n"; print "パスワード\n"; print "\n"; print "\n"; print "
\n"; print "\n"; print "
掲示板に戻る
\n"; print "
\n"; #-------------------------- # スクリプトの著作権表示 #-------------------------- print "
"; print "MultiBBS v$version
\n"; print "\n\n"; exit; } #----------------------------------------------------------------- # 削除するメッセージのリスト表示と選択画面 #----------------------------------------------------------------- sub removelist { #-------------------------- # 各種のチェック #-------------------------- if ($maintenance ne 0 ) { &error("ただ今、メンテナンス中です。"); } &check_passwd; #-------------------------- # ログを配列<@lines>に格納 #-------------------------- &read_log; &html_header("$title編集モード:メッセージ一覧"); print "\n\n"; print "
\n"; print "\n"; print "\n"; print "\n"; foreach $line (@lines) { ($count,$date,$editpwd,$name,$email,$url,$value,$subject,$rhost) = split(/\,/,$line); if ( $mode eq "user" ) { if ( $editpwd ne "" ) { $temp = crypt( $FORM{'pwd'}, substr($editpwd,0,2) ); if ( $temp eq $editpwd ) { print ""; print "削除 "; print "$count $subject "; print "投稿者:$name"; print " ($date)

\n"; print "$value\n


\n"; } } } else { print ""; print "削除 "; print "$count $subject "; print "投稿者:$name"; print " ($date)

\n"; print "$value\n


\n"; } } print "\n"; print "

\n"; print "先頭へ
"; print "\n"; print "\n"; print "

\n"; print "\n"; exit; } #----------------------------------------------------------------- # リストアップされたメッセージのデータ削除 #----------------------------------------------------------------- sub remove_data { #-------------------------- # 各種のチェック #-------------------------- if ($maintenance ne 0 ) { &error("ただ今、メンテナンス中です。"); } if ( $FORM{'target'} eq "" ) { &error("削除するメッセージが選択されていません。"); } &security_check; &check_passwd; #-------------------------- # ログを配列<@lines>に格納 #-------------------------- &read_log; foreach $line (@lines) { ($count,$date,$editpwd,$name,$email,$url,$value,$subject) = split(/\,/,$line); $del = 0; foreach $target (@RM) { if ($target eq "") { last; } if ($target eq $count) { $del = 1; } } if ($del == 0) { push(@new,$line); } } #-------------------------- # 記録ファイルへ書き出す #-------------------------- &write_log; #-------------------------- # 記録後、リロード #-------------------------- print "Location:$reload_url$script?bordname=$FORM{'bordname'}\n\n"; exit; } #--------------------------------------------------------------------- # 各種データ変数の初期化 #--------------------------------------------------------------------- sub init { if( $FORM{'bordname'} eq "" ) { &error("ボード名が指定されていません。"); } if( $path eq "" ) { $log_file = "./log/"."$FORM{'bordname'}".".log"; } else { $log_file = "$path"."log/"."$FORM{'bordname'}".".log"; } #--------------------------------- # リモートホスト名を取得 # ホスト名が取得できない場合は、 # IPアドレスを取得する #--------------------------------- $remote_host = $ENV{'REMOTE_HOST'}; if ( $remote_host eq "" ) { $remote_host = $ENV{'REMOTE_ADDR'}; } #----------------------------- # 制限中のドメインのチェック #----------------------------- if( $domain_file ne "" ) { #-------------------------------------- # IPアドレスのみの場合 nslookupで検索 #-------------------------------------- if( $remote_host=~/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/ ) { $remote_host = &nslook($remote_host); } foreach $domain (@domainlist2) { &domain_error if($remote_host=~/$domain/i); } } #------------------------------- # crypt()が使用できるかの判定 #------------------------------- $now = time; ($p1, $p2) = unpack("C2", "admin"); $wk = $now / (60*60*24*7) + $p1 + $p2 - 8; @saltset = ('a'..'z','A'..'Z','0'..'9','.','/'); $nsalt = $saltset[$wk % 64] . $saltset[$now % 64]; $pass1 = crypt( $user_pass, $nsalt); $pass2 = crypt( $user_pass, substr($pass1, 0, 2) ); if ( $pass1 ne $pass2 ) { &error("crypt()関数が利用できないので、暗号化処理ができません。"); } } #----------------------------------------------------------------- # ドメイン・エラーメッセージの出力 #----------------------------------------------------------------- sub domain_error { &html_header("MultiBBS:エラーのおしらせ"); print "

現在アクセスしているホスト情報(ドメイン)ではご利用になれません。
\n"; print "アクセスしているホスト情報は以下のように判定されています。
"; print "もし判定がおかしい場合、管理者まで連絡してください。

\n"; print "ホスト情報:$remote_host
\n"; print "\n"; exit; } #----------------------------------------------------------------- # プロキシ・エラーメッセージの出力 #----------------------------------------------------------------- sub proxy_error { &html_header("MultiBBS:エラーのおしらせ"); print "
プロキシ経由での書き込みはできません。
\n"; print "プロキシの判定がおかしい場合、以下のホスト情報を添えて"; print "管理者まで連絡してください。

\n"; print "REMOTE_HOST = $remote_host
\n"; print "HTTP_PROXY_CONNECTION = $ENV{'HTTP_PROXY_CONNECTION'}
\n"; print "HTTP_CACHE_INFO = $ENV{'HTTP_CACHE_INFO'}
\n"; print "HTTP_VIA = $ENV{'HTTP_VIA'}
\n"; print "HTTP_CLIENT_IP = $ENV{'HTTP_CLIENT_IP'}
\n"; print "HTTP_X_FORWARDED_FOR = $ENV{'HTTP_X_FORWARDED_FOR'}
\n"; print "HTTP_FORWARDED = $ENV{'HTTP_FORWARDED'}
\n"; print "HTTP_USER_AGENT = $ENV{'HTTP_USER_AGENT'}
\n"; print "\n"; exit; } #----------------------------------------------------------------- # IPアドレスからホスト名を取得する #----------------------------------------------------------------- sub nslook { local($x)=@_; local($ip,$addr); if ($x =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ){ $ip="$1.$2.$3.$4"; $addr = (gethostbyaddr(pack('C4',$1,$2,$3,$4),2))[0]; if ($addr ne "") { return $addr; } else { return $ip; } } return ""; } #----------------------------------------------------------------- # 各種のセキュリティ対策 #----------------------------------------------------------------- sub security_check { #---------------------------------------------- # IPアドレスのみの場合 nslookupで検索 #---------------------------------------------- if( $remote_host=~/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/ ) { $remote_host = &nslook($remote_host); } #-------------------------------------------------- # 制限中のドメインのチェック #-------------------------------------------------- foreach $domain (@domainlist1) { &domain_error if($remote_host=~/$domain/i); } foreach $domain (@domainlist2) { &domain_error if($remote_host=~/$domain/i); } #-------------------------------------------------- # 外部からの書き込みチェック(POSTのみ許可) #-------------------------------------------------- if ($ENV{'REQUEST_METHOD'} ne "POST") { &error("method=getでの投稿は受け付けられません。"); } #-------------------------------------------------- # 外部フォームからの書き込みの禁止チェック #-------------------------------------------------- if ($script_url ne "") { $ref = $ENV{'HTTP_REFERER'}; $ref_url = $script_url; $ref_url =~ s/\~/.*/g; if (!($ref =~ /$ref_url/i)) { &error("「$script_url」以外からの投稿は受け付けられません。"); } } #-------------------------------------------------- # 各種のセキュリティ処理 #-------------------------------------------------- if ( $CFG_DATA{'security'} eq "1" || $CFG_DATA{'security'} eq "3" ) { #---------------------------------------------- # JPドメインの判定 #---------------------------------------------- $temp = reverse $remote_host; if ( "pj." ne substr( $temp, 0, 3 ) ) { &domain_error; } } if ( $CFG_DATA{'security'} eq "2" || $CFG_DATA{'security'} eq "3" ) { #---------------------------------------------- # プロキシの排除 #---------------------------------------------- $proxycheck = 0; $proxycheck = 1 if($ENV{'HTTP_PROXY_CONNECTION'}); $proxycheck = 1 if($ENV{'HTTP_CACHE_INFO'}); $proxycheck = 1 if($ENV{'HTTP_VIA'}); $proxycheck = 1 if($ENV{'HTTP_CLIENT_IP'}); $proxycheck = 1 if($ENV{'HTTP_X_FORWARDED_FOR'}); $proxycheck = 1 if($ENV{'HTTP_FORWARDED'}); $proxycheck = 1 if($ENV{'HTTP_USER_AGENT'}=~/via/i); if( $proxycheck == 1 ) { $proxycheck2 = 1; foreach $temp2 (@proxylist) { $proxycheck2 = 0 if($remote_host=~/$temp2/i); } if( $proxycheck2 == 1 ) { &proxy_error; } } } } #----------------------------------------------------------------- # フォーム投稿されたデータを解析し、配列にリストする #----------------------------------------------------------------- sub form { #-------------------------------------------------- # フォームから入力されたデータを$bufferに格納 #-------------------------------------------------- if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } #-------------------------------------------------- # $bufferに格納されたFORM形式のデータを取り出す #-------------------------------------------------- @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; #-------------------------------------------------- # 削除するメッセージ番号のリストアップ #-------------------------------------------------- if ($name eq "target") { push(@RM,$value); #---------------------------------------------- # 親メッセージの場合、コメントの有無に関わらず # コメントもリストアップする #---------------------------------------------- if ( substr($value, 0, 1) eq "#" ) { for( $i=0; $i<$max_comment; $i++ ) { $temp1 = substr( $value, 1, 4 ); $temp2 = sprintf ("@%s%02d", $temp1, $i); push(@RM,$temp2); } } } $FORM{$name} = $value; } } #----------------------------------------------------------------- # ボード定義ファイルの読み込み #----------------------------------------------------------------- sub read_cfg { if( $path eq "" ) { $cfg_file = "./log/"."$FORM{'bordname'}".".cfg"; } else { $cfg_file = "$path"."log/"."$FORM{'bordname'}".".cfg"; } if (!open(DB,"$cfg_file")) { &error("ボード定義ファイルをオープンできません。"); } eval { flock( DB, 1 );}; # ファイルをロック @lines = ; close(DB); eval { flock( DB, 8 );}; # ロック解除 foreach $line (@lines) { ($name,$value) = split(/\,/,$line); $CFG_DATA{$name} = $value; } if ( $CFG_DATA{'security'} eq "" ) { $CFG_DATA{'security'} = $security; } } #----------------------------------------------------------------- # 管理用マスターキーの読み込み #----------------------------------------------------------------- sub read_master_key { $pwd_file = "$path$passwd_file"; if ( open( DB, $pwd_file)) { eval { flock( DB, 1 );}; # ファイルをロック $master_pass = ; close(DB); eval { flock( DB, 8 );}; # ロック解除 if ( $master_pass eq "" ) { print "Location:$reload_url"."admin.cgi\n\n"; } chop($master_pass) if $master_pass =~ /\n$/; } else { print "Location:$reload_url"."admin.cgi\n\n"; } } #----------------------------------------------------------------- # ドメインリストの読み込み #----------------------------------------------------------------- sub read_domainlist { if( $domain_file eq "" ) { return; } $filename = "$path"."$domain_file"; if (!open(DB,"$filename")) { &error("ドメインファイルが見つかりません。"); } eval { flock( DB, 1 );}; # ファイルをロック @data = ; close(DB); eval { flock( DB, 8 );}; # ロック解除 foreach $temp (@data) { ($domain,$level) = split(/\,/,$temp); if ( $level eq "0" ) { push( @domainlist1, "$domain" ); } else { push( @domainlist2, "$domain" ); } } } #----------------------------------------------------------------- # ログファイルの読み込み(@linesに格納) #----------------------------------------------------------------- sub read_log { if (!open(DB,"$log_file")) { &error("ファイルの入出力にエラーが発生しました。"); } eval { flock( DB, 1 );}; # ファイルをロック @lines = ; close(DB); eval { flock( DB, 8 );}; # ロック解除 } #----------------------------------------------------------------- # ログファイルの書き出し #----------------------------------------------------------------- sub write_log { if (!open(DB,">$log_file")) { &error("ファイルの入出力にエラーが発生しました。"); } eval { flock( DB, 2 );}; # ファイルをロック print DB @new; close(DB); eval { flock( DB, 8 );}; # ロック解除 } #----------------------------------------------------------------- # パスワードのチェックと、モードの判定 # ※入力されたパスワードを判定し、管理者・主催者・ユーザー # の各モードを決定する #----------------------------------------------------------------- sub check_passwd { if ( $FORM{'pwd'} eq "" ) { &error("パスワードが入力されていません。"); } $temp1 = crypt( $FORM{'pwd'}, substr($CFG_DATA{'user_pass'},0,2) ); $temp2 = crypt( $FORM{'pwd'}, substr($master_pass,0,2) ); if ( $temp1 eq $CFG_DATA{'user_pass'} ) { $mode = "owner"; $title = "オーナー"; } elsif ( $temp2 eq $master_pass ) { $mode = "admin"; $title = "管理者"; } else { $mode = "user"; $title = "ユーザー"; } }