gateシステムのスクリプトに対する質問事項 ■ gate-daily - gate daily work script ※gate-daily コマンドのオプションについて※ オプションに -v をつけた場合, 子プロセス(gate-db-to-passwd, gate-db-to-shadowなどなど) にも -v オプションをつけるのだが, 実際に -v オプションを受け取るのは gate-db-to-sudoers gate-db-update gate-ip-update のスクリプトのみである. これらは &Getopts でオプションを読めるようなスクリプトになっている. つまり, この他のスクリプトはそのように書いていないため オプション自体が読めない ・オプションに -N がつく場合  /etc/inetd.conf から gate-daily を起動する場合、    /usr/local/lib/gate/gate-daily -N  となっている。つまり、デーモンが動く際には -N オプションが使用される    ※この -N オプションの際に具体的にどういった事をしているのかは  今のところわからず 予想  出力されなくしている? →<cgiの結果を待たずに接続をきってしまう(待たされないため)>  <shudsown の下の open は出力、エラー出力の出力を吐かせるためにある> ・始めの方の $rcsid = '$Id: gate-daily,v 1.20 1999/12/20 13:40:42 mym Exp $'; とはなんぞや? 他のスクリプト全てに書いてあるけど? →<CVS が勝手に書いてくれるもの> ・バッファリングとはどういうことですか?    $| = 1; とすると、「自動的に出力バッファをフラッシュする」などと 本には書いてあるのですが、スクリプトのコメント文とどっちが正しいのでしょう?    →<「バッファリングする」→メモリに貯めておくこと>     <「バッファをフラッシュする」→メモリから消去する> こういうこと ・&run("/etc/init.d/bind reload") if (&Hostname eq $DNS_SERVERS[0]); とあるが、blueではreloadしなくて良いのか? →<blueはreloadしない。2ndDNS はprimaryDNSから     情報をいただく(これはbindの仕事)> ・&run("$SBINDIR/tcp_smtp_cdb") if (-x "$SBINDIR/tcp_smtp_cdb"); とあるが、tcp_smtp_cdbは実行不可になってますけど… (というか、tcp_smtp_cdbってなんですか?) →<これはメール関係のスクリプトなのでmailサーバでのみ動かす。   gateに登録されているipからのメールしか受け付けないようにしている。   (くわしいことはmailサーバ構築ドキュメントに)> ・以下って何の為にあるんですか? if ($USE_DAEMON) { ($fakename, $fakepasswd, $gateuid) = getpwnam($GATE); $> = $gateuid; $< = $gateuid; print "$0: i am ", `whoami` if $opt_v; }    →<ここまでは root 権限でスクリプトを実行していたが、 gate-ip-update , gate-db-update に関しては gate さんになってから実行したほうが良いので、 (rootでの転送は非常に危険)なりかわって実行している> ■gate-sync.d 何が何やらさっぱりわからず  (どうやら現在は使われていないようなので無視してよいか?)  →現在は使用していない ■gate-db-update  ・&Hostname →orangeのマシンなら  「orange.ep.sci.hokudai.ac.jp」という文字列が出てくる ・&HostOption で return $hostname eq $DBSERVER; $hostname と $DBSERVER が同じ文字列であれば サブルーチンの外に 1(真)を返し、 $hostname と $DBSERVER が異なる文字列であれば サブルーチンの外に 0(偽)を返す。  ・rsync について rsync とは他のコンピュータ(自コンピュータも含む) にデータを転送するソフト オプション解説   -a archive (ファイルについての情報を保つ)   -u update (より新しければ更新しない)   -v verbose (-vv more verbose)   -z compress with zlib (電話線経由ならずいぶん速くなります)   -b backup (古いファイルは ~ の付いた名前になる) -e ssh sshを使用して転送 --delete 転送元に無くて, 転送先にあるファイルは rsync を 使用した際に削除される.  ・$client と ${client} の違いは? 多分、普通の'文字'とくっついてしまわないような配慮と思われる   →想像どおり    ・&run →引数を全て並べて、それをコマンドとして実行  ・if (($? >> 8) & 0xFF) { 0xFF → 16進数における「FF」のこと。10進数になおせば「255」 2進数になおせば「11111111」 ($? >> 8) → サブプロセスが返した実際の終了値 & → ビット単位での論理積 例 5 & 12 = 4 5 → 0101 12→ 1100 4 → 0100 ($? >> 8) & 0xFF →($? >> 8)の値が 1 〜 255 であれば真、それ以外では偽が返る  ・&connectToGateSyncd →難しいため、後に回す  ・ssh -x → ssh -X の逆で、接続先からX11 を飛ばしてこないようにする ・&run('/usr/bin/ssh', @ssh_opt, $client, "$LIBDIR/gate-daily",@remote_daily_opt); →ssh で転送先のホストに入り、/usr/local/lib/gate/gate-daily を実行する  ・gate-db-update における、デーモンモードとクーロンモードの違い デーモンモード → 転送先のホストの/home/gate/userdb/ 以下を書き換えた際に   転送先ではinetd(?)のgate   (つまり、/usr/local/lib/gate/gate-daily -N)が実行される。               転送元では出力の表示がなされる   ※実際にはどのタイミングで起動されるのか? クーロンモード → 直接転送先の gate-daily を起動させる  ・コマンド実行の順 gate-daily(www)[gateポートに通信があった場合] →gate-db-to-* ,gate-make-home,gate-remove-home,tcp-smtp_cdb及び  gate-ip-update, gate-db-update →gate-daily(www以外) [gate-db-updateによって起動される(daemon mode 時は間接的に)] →gate-db-to-* ,gate-make-home,gate-remove-home,tcp-smtp_cdb "/etc/init.d/bind reload"(Primary dnsのみ) ■gate-ip-update ※・マニュアルについて  http://www.ep.sci.hokudai.ac.jp/~gate/doc/gate-ip-update.htm や   man gate-ip-update などには   「クーロンモードでは ssh(1) を使用しデーモンモードでは gate-syncd(8)   を介して配送先の gate-daily(8) を起動します。」   とあるが、Perlスクリプトにはそのような記述は無い   (デーモンモードでは具体的にどのように gate-dailyが動いているのか   理解していないので確証は無いが、クーロンモードの場合はgate-db-update にあった記述がこちらには無いので、間違いない)   →<man の記述間違いらしい gate-daily では gate-ip-update の後に gate-db-update があるため gate-db-update が動いたときに ssh で転送ホストの gate-dailyを 起動している。> ■gate-db-to-group  □&getStableUsers は &getUsersByDirectory を読み込む   ・スクリプトが読めない # たとえば . で始まったり ~ で終わったりする名前は無視 next unless $entry =~ /^[-a-z0-9]+$/;       →この正規表現がわからない → <これはログイン名が a〜z , 0〜9 及びハイフン でのみ   からなる場合のみ @users に加えられる>   ・&getStableUsers [引数なし] →@users = (akihiko,akira,…,morikawa,…,yuuichi3,yyhlab) [/home/gate/userdb/stable/ 以下にあるものが配列として出力]   ・&getUsersByDirectory(/home/gate/userdb/stable)   →@users = (akihiko,akira,…,morikawa,…,yuuichi3,yyhlab) 1. 通常のファイルでないものは除外 2. 「.」で始まったり、「~」で終わったりするものも除外 □B.2 /etc/passwd より UID と ユーザ の対応を知る   ・間違い? # /etc/passwd の各行より UID と ログイン名 からなる連想配列を生成 # /etc/gdsswd の各行を読み込む # 配列 @passwdfield に /etc/passwd の field を : で分割したものを代入 →真中の /etc/gdsswd って何?  →<書き間違い> →スクリプトを見ると、/etc/group からの読み込みのようだけど? →<スクリプトの間違い。本当は /etc/passwd からよみこむべき>   ・close 文の不思議     open(GROUPFILE, "<$GROUP_FILE") なのに、 close PASSWDFILE;     なのはなんで? →<close 文の書き間違い>  □C. /etc/group へ書かれるユーザの選択   ・間違い? open(GROUPFILE, "<$GROUP_FILE") なのに、 close SHADOWFILE; なのはなんで? →<close 文の書き間違い> ・&isaSystemUser($UID{$user}) →$UID{$user} [$user の uid の数値]が  1000 〜 29999(一般ユーザ用uid) であれば 偽  それ以外(システムユーザ用uid)であれば 真  が返る。  □D. ファイル生成 D.1 テンポラリーファイルの生成 →新規作成の際は 個人ユーザも法人(グループ)ユーザも同様に  /etc/group に書き込む    ◆ &readCard (morikawa) →%field = ( 'name' , 'Morikawa Yasuhiro', 'type' , 'person', 'uid' , '1339', 'syozoku' , '北海道大学理学部地球科学科(地球物理学)', ... 'date' , '2001-04-13T14:20:34+0000', 'fax' , '' )    ・$cardpath = &getCardPathByUser(morikawa) → $cardpath = /home/gate/userdb/stable(又はpending,defunct)/morikawa    ・$cardfile = &openForReading($cardpath) # $cardpath=/home/gate/.../morikawa → $cardfile = /home/gate/.../morikawa (この右のファイル名自体がファイルハンドルとして使用される.) つまり, この $cardfile はファイルハンドルになっている なお, $cardpath が定義されていないときは, 標準入力(STDIN) がファイルハンドルとなる.    ・&readCardStream($cardfile) →%field = ( 'name' , 'Morikawa Yasuhiro', 'type' , 'person', 'uid' , '1339', 'syozoku' , '北海道大学理学部地球科学科(地球物理学)', : : 'date' , '2001-04-13T14:20:34+0000', 'fax' , '' )  jcode.pl → 漢字コードを変換したりするスクリプト   &jcode'convert(*_, "euc") →$_ の中身(日本語)の漢字コードを euc にする。 ちなみにこちらが jcode.pl の作者さんのHP http://www.srekcah.org/jcode/ で, こっちが私的な解説書 http://www.mikeneko.ne.jp/~lab/kcode/jcode.html   ● &make_group_field(morikawa mym kosugita uwabami miumiu)  →$group_field =morikawa,mym,kosugita,uwabami,miumiu 1. 行末の改行文字を削除 2. 行頭の空白を削除 3. 行末の空白を削除 4. 残った空白をカンマに変換して返す まとめ(ちなみにこのサブルーチンは gate-db-to-group 内にある)   /home/gate/userdb/stable 以下にあるグループ(法人)ユーザアカウント情報   から、/etc/group に書き込む情報を生成する  □D.2 テンポラリーファイルを /etc/group へ移動   ・mv -f → 移動する際に、移動先のファイルがあっても、何もきかずに上書きする ■gate-db-to-passwd  □2.1 データベース登録済みユーザを採用   ・&userLimit(akihiko,akira,…,morikawa,…,yuuichi3,yyhlab)   → 引数 をそのまま返す [&HostOption('user')で偽が帰ってきた場合]   → epdns, epdns の member, epdns の保証人 のみを返す [yellow,blue]   → epnews, epnews の member, epnews の保証人 のみを返す [white]   このサブルーチンによって、www,mail以外のサーバは、    その管理者以外のユーザーがログインすることを禁止している  /etc/gate.conf の %DB_SHARE_HOST の中身と連動している  ことに注意    ・途中で &HostOption('user') → $limit = 0(偽) を返す (www,mail) → $limit = epdns を返す (yellow,blue) → $limit = epnews を返す (white)       ・途中で &stableUserExists (epdns) → 引数をそのまま出力  (与えられた $username がデータベースの承認済み領域[stable] に存在する場合のみ) ・&makePasswdEntry(%card) [ %card=&readCard($user) ]   (これはこのスクリプトでのみ使用) → morikawa:x:1339:1339: … :/home/morikawa:/bin/bash %card = ( 'name' , 'Morikawa Yasuhiro', 'type' , 'person', 'uid' , '1339', ... 'date' , '2001-04-13T14:20:34+0000', 'fax' , '' ) %card のデータを /etc/passwd 用に変換するサブルーチン ※よくわからない部分   local($gcos) = ($card{'name'} . ',' . $card{'phone'});  →このドットは文字列の連結に使用されている? # なければ nobody 化する  →そこまで作成されてたデータはどうなっちゃうんですか?   local($uid) = (($card{'uid'} + 0) || 65534);   local($gid) = (($card{'gid'} + 0) || ($card{'uid'} + 0) || 65534);  →この「+ 0 」はなんですか?   ・$HANDLE = &openForWriting($TEMP_FILE)  [このスクリプトでは$TEMP_FILE = /tmp/passwd]    →$TEMP_FILE というファイルに入力できるような ファイルハンドルを返す. ファイルハンドルは $HANDLE として扱われる. (ファイルハンドル使用終了時に 「close $HANDLE;」 する必要がある) よくわからないところ   return "STDOUT" unless $filename;  →具体的にどうなるんすか? ■gate-db-to-shadow ※バグ※ /etc/shadow に既に消えたはずの(defunct以下にあるもの) ユーザの情報が残ってしまっている. □前準備 ・ $TEMP_SHADOW_FILE = "/tmp/shadow"; → 作成途中の shadow ファイルを置いておく場所として, /tmp/shadow を作成し, 利用する. ・ %IN_SHADOW = (); # /etc/shadow 既存エントリのあるユーザなら真 → 実はこの連想配列はスクリプト内には存在しない. $OLD_ENTRY{$user} が真か偽かで判定できてしまうため 使われなくなったらしい. どうも昔は %IN_STABLE という連想配列が使われていたらしい (すくなくともバージョン1.34までは使われている) 最新バージョンの1.45で %IN_SHADOW という連想配列ができていた. 編集したのは mym さんのようである. わからないこと → こういったものは残しておくべきものなのかな? □書き込むべきユーザを配列 @stableUsers に書き込む. ・ @stableUsers = &userLimit(&getStableUsers); → www, mail → stable 領域以下にある, 全てのユーザ名   → dns → epdns, epdns の member, epdns の保証人 のみ   → news → epnews, epnews の member, epnews の保証人 のみ □ passwd ファイルから ユーザ名,UIDの連想配列(%UID)を取得 □ shadow ファイルから ユーザ名,shadowファイル内のそのユーザのエントリの 連想配列(%OLD_ENTRY)を取得 □ stable 領域にあるユーザについて, %NEW_ENTRY に ユーザ名, shadow ファイルに書き込む情報の連想配列 を書き出す. 新規ユーザについては %NEW_ENTRY に書き込む情報を作成すると同時に 通知メールを発送する. メールの発送については以下の 「□新規ユーザ及び承認した保証人へメールで通知」 を参照 ◆%OLD_ENTRY に既に書き込むべき情報があるユーザの分はそのまま %NEW_ENTRY に書き出される. (こうしないとパスワードが保持されない) ◆%OLD_ENTRY に書き込むべき情報が無かったユーザは 新たに書き込むべきエントリを作成し, %NEW_ENTRY に書き出す. それぞれのユーザに固有な情報は, ・ユーザ名 → $user ・初期パスワード → $card{'password'} ・最終パスワード変更(作成)日時 → $today (1970年1月1日からパスワード最終変更日時迄の日数) の3つで, 新規ユーザのエントリを作成するために この3つはこのスクリプトで作成される. $user は@stableUsers が一つ一つ代入されることで作成され, $card{'password'} は サブルーチン &readCard($user) で作成される. $today の作成方法は以下で説明する. ・time関数 $today = int(time / 86400); time → 協定世界時(UTC)の1970年1月1日からの経過秒数を返す。 int(EXPR) → EXPR の整数部を返す time / 86400 → time を86400 で割る (86400 → 一日の秒数) つまり, この操作によって $today は1970年1月1日からの経過日時となる. ・新規ユーザと既存ユーザとのパスワードの取り扱いの違い 新規ユーザーのパスワードは /home/gate/userdb/stable/    以下にある passwd 欄からそのままコピーされる    (既存ユーザのパスワードは変更されない)    (/home/gate/userdb/stable/ 以下のパスワード欄には 初期パスワードがずっと残る) □新規ユーザ及び承認した保証人へメールで通知 このスクリプトがユーザ及び保証人にアカウントが 作成されたことをメールする 新規ユーザのエントリ($NEW_ENTRY{$user})が作成された 際に, メールの送信が行われる. (既存ユーザ分の $OLD_ENTRY{$user} が $NEW_ENTRY{$user} にコピーされる 際には, メールの送信は行われない.)   ・サブルーチン announceMail &announceMail が実際のメールを送るサブルーチン(ローカルなサブルーチン)   ・&announceMail(%card) [%card : ある一名のデータベースの連想配列]     →保証人のメールアドレス(〜@ep.sci.hokudai.ac.jp) と 新規登録されたユーザのメールアドレス (gate登録した際の連絡先メールアドレス)へ アカウントが発行されてログインができるようになった旨 を伝えるメールを送る. なお, 送信するのはgate登録システムのデータベースサーバ つまり, 専攻サーバでは www サーバが行う. このため, wwwサーバには qmail がインストールされている必要がある. わからないこと $MAILSERVER という引数が /etc/gate.conf , /usr/local/lib/gate/gate-common.pl ともに無い ※ $MAIL_SERVER はあるんだけど… $MAILSERVER を出力させるプログラムを作ってみればよい? 作ってみた結果 → ~/bin/mailserv.pl という, /etc/gate.conf をインクルード(require) してから, $MAILSERVER , $MAIL_SERVER を出力する スクリプトを作ってみた結果 やはり, $MAILSERVER というスカラー変数には何も入って いないことが確認できた. つまり, 今までは保証人(hosyonin)へのメールは To: hosyonin@grey.ep.sci.hokudai.ac.jp に送られていたわけではなく, To: hosyonin へ送られていたことになる. おそらく @toAddress = ($card{'hosyounin'} . $MAILSERVER); を @toAddress = ($card{'hosyounin'} . \@$MAIL_SERVER); とすればよいと思われる.    ・通常表記日時作成用サブルーチン &readableDate($card{'date'}) (実際はこのサブルーチンは &openMail と &printMail の間に実行される) → $card{'date'} = '2001-04-13T14:20:34+0000' という引数をとって, (引数をとらない場合については演算子の説明の後) 2001年04月13日 23時20分34秒 という形式の文字列を返す. +9時間して, UTCを日本時間に直している. うるう年の2月や2000年, 2001年などにも対応している. ・剰余演算子「%」 $x % $y この式は $x を $y で割った余りが返る. ・条件演算子「条件式 ? 式 : 式」 つまり, $monthlen = ($y % 4) ? 28 : 29; では, $y が4の倍数でない時(つまり $y % 4 が真の時), $monthlen に 28 が代入される. $y が4の倍数の時(つまり $y % 4 が偽の時), $monthlen に 29 が代入される. ・引数をとらない場合 引数をとらずに &readableDate() を動かすと, $time = gmt_date unless defined $time; の行でサブルーチン gmt_date が実行されて, 返った値が $time に代入される. この場合 gmt_date は組み込み関数として動作する. このため, プロトタイプ (;$) が有効となる. つまり, gmt_date は1つ以下の変数をとることが できるということである. で, 結果, gmt_date が実行された時間が $time = 2001-04-13T14:20:34+0000 という形式で出力される. で, 結局はこれが上記の形式に 変換されて出力されることになる.    ◆メール送信用サブルーチン メール送信用のサブルーチンは openMail, printMail, closeMail の3つでセットになっている. ◇&openMail("user toroku for $username done at $hostname", $MAILADDR, @toAddress); →1.送られた引数から作成したメールのヘッダ部分 (To: , Subject: など) を /tmp/gatemail.$$ ($openMail_file) に書き出す. 2.出力用にオープンしたファイルハンドル MAIL は保持されたまま 残る. つまり以下の式の open はサブルーチンを出た後でも有効. open(MAIL, ">$openMail_file") 3.$openMail_mailto にこのメールの宛先アドレスを列挙する. (ローカル変数でないので, サブルーチンから出た後でもつかえる.) 4. jcode.pl をrequire する. これは 次の &printMail で使用される. sub openMail($$@) の $$@ って何ですか? → これは「プロトタイプ」と呼ばれるもので, このサブルーチンが 受け取る引数の数や型に制限を加えることができる. ただし, このプロトタイプが影響を及ぼすのは 「& を使わない呼び出し」のときのみ(つまり, 組み込み関数の ようにサブルーチンを用いたときのみ)である. 参考 プログラミングPerl P133〜 ちなみに「$$@」は引数として, スカラー変数, スカラー変数, 配列 をとるということを示す. ・3つの引数について 基本的にopenMailは3つの引数をとる. 1つめは 送信するメールの題名 ($subject) 2つめは 送信者. デフォルトでは $MAILADDR = gate@ep.sci.hokudai.ac.jp となっている. ($from) 3つめは 宛先のアドレス これはスカラーではなく配列になっており, 複数人に メールを送信できるようになっている. (@to) ユーザ登録の際の「本人の連絡先電子メールアドレス」 と保証人のメールアドレス($hosyounin@ep.sci.hokudai.ac.jp)に の2箇所に送られる. ※「本人の連絡先電子メールアドレス」を空欄にした場合, 送られるのは保証人のみ ・$openMail_file = "/tmp/gatemail.$$"; /tmp/gatemail.$$ を メールの一時書き出しファイルとして 設定する. ($$ はこのスクリプトを実行している Perlのプログラムのプロセスid番号) この後, unlink コマンドでいったん $openMail_file は削除されて, その後, open(MAIL, ">$openMail_file") で書き出し用の ファイルハンドルに設定される. ・print MAIL "To: 〜 これ以降の6つの print文でメールのヘッダ部分(To: とか Subject: とか) を /tmp/gatemail.$$ に書き出す. ・print MAIL "Date: ", &rfc822_date(), "\n"; &rfc822_date() は gate-common.pl にあるサブルーチン. 現在の時刻(現在時刻は time関数で得る)を Mon, 19 Nov 2001 05:25:33 GMT といった形式にして返す. なお, 引数を指定してある場合はその時間を上記のような形式にして 返す. (引数は「協定世界時(UTC)の1970年1月1日からの経過秒数」を与える 必要がある.) ※ このサブルーチンのプロトタイプ (;$) について これは「スカラー変数を一つのみ取る(省略可)」という意味である. ・print MAIL "Reply-to: $REPLY_MAILADDR \n"; デフォルトでは $REPLY_MAILADDR="netcom-query@ep.sci.hokudai.ac.jp" つまり, openMail というサブルーチンを使ってメールを配送する と, 必ず Reply-to: netcom-query@ep.sci.hokudai.ac.jp というヘッダがつく. ちなみに, これは やまだ(まなぶ)さんが 2001年5月あたりに 加えたものらしい. わからないこと Reply-to: の後にアドレスをいれたのだが そのアドレスにメールが送信されない. どういうこと? (netcom-query@ep.sci.hokudai.ac.jp へのメールを受けている えらい人にちょっと聞いてみようか?) →現状の理解 --後で調べてみたがどうやら正しいらしい-- 「Reply-to」というのは「返答はこっちにしてね」 といったような意味合いのものである. openMail を使用した場合, 送信元(From:) は gate@ep.sci.hokudai.ac.jp になるのだが, そちらに メールを送られても困るため, 返信先はネットワーク委員会 にするため, このような設定になった. ・$openMail_mailto = join(", ", @to); $openMail_mailto というスカラー変数に宛先となったメールアドレス が列挙されて代入される. ◇&printMail(< mailformat_jis.txt こうすると文字コードEUCのファイル mailformat.txt から 文字コードJISのファイル mailformat_jis.txt を作成する ことができる. □ %OLD_ENTRY のシステムユーザの行をそのまま %NEW_ENTRY へコピー これで, システムユーザ, 既存ユーザ, 新規ユーザ の全てが %NEW_ENTRY に書き込まれた. □ 出力すべきユーザのリストをUID順に並び替える. @users = keys %NEW_ENTRY; とすることで, %NEW_ENTRY のキーの一覧(アカウント名の一覧)を @users に代入 @users = sort { $UID{$a} <=> $UID{$b} } @users; とすることで, @users を UID順に並び替える. (ここでも %UID [ユーザ名とUIDが対応した連想配列]が使用される) □ $TEMP_SHADOW_FILE (= /tmp/shadow ) をオープンし, %NEW_ENTRY を @users の順に(つまりUID順に) $TEMP_SHADOW_FILE へ書き込む. (これが /etc/shadow になる.) □ 現 /etc/shadow ファイルを /etc/shadow.bk にコピーして パーミッションを 640 とする. 現 /tmp/shadow を /etc/shadow へ mv し, パーミッションを 640 とする. これで gate-db-to-shadow のスクリプトは終了する. ■gate-db-to-zone □primaryDNSかどうかの判定 unless (&Hostname eq $DNS_SERVERS[0]) { exit 0; } → ホスト名が primary DNS server と一致しない場合は終了 つまり /var/named/ を持っていることを前提として これより下のスクリプトは実行される □zone ファイルのヘッダ部分の元ファイル $zoneHeaderFile = "$DB_IP_ZONE/zone.head"; 専攻サーバでは $DB_IP_ZONE = "$DB_IP_BASE/zone" $DB_IP_BASE = '/home/gate/ipdb'; なので, DNSサーバの /home/gate/ipdb/zone/zone.head がヘッダファイルの元といえる. ※ ただし, /home/gate/ipdb/ 以下の内容は gate-ip-update で データベースサーバ(www)のものが クライアントホスト(www以外) にコピーされるので,本当の元祖のヘッダファイルは www の /home/gate/ipdb/zone/zone.head である. また,他にDNSサーバの設定ファイルとして /var/named/local.rev というファイルもあり,これに書いてある内容と /var/named/ep.zone の内容が一致するようにしておくこと ※以前にこれがずれており,そのために一時不安定に なったのではないか? と考えられている. □新たな /var/named/ep.zone が作成されるまでのだいたいの流れ ・前提 実は /var/named/ep.zone と /var/named/ep.zone.edit は 同じファイルである(ハードリンク). (「$ ls -li」コマンドで見てみるとよい ) ・流れ まず, ep.zone.edit の方を「unlink」コマンドで削除する. その後すぐに新しく真っ白な ep.zone.edit を作成し, それに zone.head と ipdb/stable/ 以下の データを書き込む (詳細は下記参照) そして,完成したら 元の ep.zone を「unlink」コマンドで削除し, 今度は 「link(ep.zone.edit , ep.zone)」コマンドで ep.zone.edit のハードリンクを ep.zone として作成する. □IPデータベース(stable)中のファイル名のリストを返す ・ &listStableHosts() →これは gate-db-to-zone 内にあるサブルーチン ・解析 コマンド $ gate-ip-list stable を使用して ipdb 以下の stable 領域内にあるホスト名のリストを とりだし, @hostList という配列に並べる わからないこと コマンドを以下のように使用しているが $ gate-ip-list stable 2>&1 ^^^^ これは何ですか? □ホスト名とその情報が対応する連想配列を作る ・ &getHostsInformations(@stableHosts) @stableHosts の内容は 上記のサブルーチンで取り出した @hostList と同じ →結果 %hostsInformations = ('joho3' , 'accepted: … root:uwabami&type:A', 'joho6' , 'accepted: … root:koko&type:A', … 'joho24', 'accepted: … root:keisly&type:A') ・ 解析 $ gate-ip-show -c @stableHosts 2>&1 →コマンドでホスト一つ一つについてCGI形式の情報を 取り出す. → これをファイルハンドル INPIPE に入れる while ($ls = ) { ($hostname, $info) = split(/=/, $ls, 2); $hostsInformations{$hostname} = $info; } → CGI 形式で出力されたデータは 「ホスト名 = CGI形式の情報」といった形になっているので, splitコマンドでそれぞれ変数に代入され, それが連想配列になる 以上で必要な情報は集まったことになる. □追加書き出し用ファイルを削除して開く ・ 関数 unlink $ unlink "$tyuukanFile" # $tyuukanFile = /var/named/ep.zone.edit → ep.zone.edit ファイルを削除 ・ $tyuukanFileHandle = &openForAddWriting($tyuukanFile); 結果 → この行の前では $yuukanFile = ep.zone.edit (ファイル名) であり, この行の後では $yuukanFileHandle = ep.zone.edit (ファイルハンドル名) となる ^^^^^^^^ &openForAddWriting($tyuukanFile) 結果 → ep.zone.edit ($tyuukanFile) を追加書き出し可能な ファイルハンドルとして返す ファイルハンドル名は 「ep.zone.edit」となる. ・&openForWriting と違う点は open($filename, ">$filename") が open($filename, ">>$filename") となっていること 分からないこと どんな時に追加書き込みが必要なのか? ・return "STDOUT" unless $filename これについては, ■ gate-db-to-passwd の &openForWriting に同じ疑問がある. ・ umask((umask) & ~0660) おそらく, umask で現在の値を出し,それと 066 又は 660 との論理積をとってるように思うのだけど… umask については下記参照 分からないこと この行で具体的にどういったことが行われているのか わからない 0 → 000 2 → 010 6 → 110 2 & 6 → 2 0 & 6 → 0 0 & 2 → 0 ・ umaskについて umask とはファイル(もしくはディレクトリ)を作成する際に どのようなパーミッションがかかるのかを決めるものである. 現在どのような値になっているのかは $ umask コマンドで見ることができる. また, umask は任意に設定でき, $ umask 022 などとすることで変更することができる. この数値は1桁目がユーザ, 2桁目がグループ, 3桁目が他人 についての設定になっている. (ここはchmodと似ている) しかし,数値の内容については chmod で設定する値とちょうど 逆になっており, 1 → 実行権限を与えない 2 → 書き込み権限を与えない 4 → 読み取り権限を与えない と言う内容になっている. つまり, 022 ならば グループ,他人には書き込み権限を与えない ことになっている. ※なお,専攻サーバの設定では,ファイルは作った際には 実行権限が付かない. つまり022ならば, -rw-r--r-- というパーミッションになる □読み込み用ファイルをファイルハンドルとして開く $readingHandle = &openForReading($zoneHeaderFile); 結果 → ファイルハンドルとして $readingHandle = zone.head を返す. □ ヘッダの書き出し &writeSoaRecord($readingHandle, $tyuukanFileHandle); 結果 → ep.zone.edit に zone.head の数箇所を置換したものを書き込む ^^^^^^^^^^^^^^^^^^^^ ・ 解析 zone.head ファイルの数箇所を置換して ep.zone.edit ファイル に書き込む. ・ 置換する内容 SERIAL → $serial (&makeSerialNumberで生成される) DNS_SERVER_1ST → プライマリDNSサーバのドメイン名 (gate.conf に $DNS_SERVERS[0] として設定されている値) MAIL_ADDR → postmaster.ep.sci.hokudai.ac.jp (gate.conf に $POSTMASTER として設定されている値) 置換して書き出し用ファイルハンドル(ep.zone.edit)に書き出す ・ &makeSerialNumber 現在時刻を10桁表示する. 結果 → 2001年 11月 13日 正午 ならば $serial = 2001111350 という値が変える. わからんこと このシリアルナンバーは何のためにあるのかい? □ 1stDNS, 2ndDNS, mail サーバをep.zone.edit に書き込む &printNsRecord($tyuukanFileHandle); ・ &returnAddString($dnsserver); # $dnsserver = yellow.ep.sci.hokudai.ac.jp blue.ep.sci.hokudai.ac.jp 結果 → 以下の2行が ep.zone.edit に書き加えられる. ep.sci.hokudai.ac.jp. IN NS yellow.ep.sci.hokudai.ac.jp. ep.sci.hokudai.ac.jp. IN NS blue.ep.sci.hokudai.ac.jp. □ Aレコード, Mx, Cnameとホスト名を書き出す ・ &printZoneFileEntries($tyuukanFileHandle, %hostsInformations); $tyuukanFileHandle = ep.zone.edit (ファイルハンドル) %hostsInformations = ('joho3' , 'accepted: … root:uwabami&type:A', 'joho6' , 'accepted: … root:koko&type:A', … 'joho24', 'accepted: … root:keisly&type:A') 結果 → %hostInformations からの情報から, それぞれの タイプに応じた(/var/named/ep.zone書体になっている) 形で, 各情報が ep.zone.edit に書き加えられていく. ・ %info_card = &parseCookie($info); # $info = ある一ホストのIPデータベースのCGI形式の情報 結果 → 以下のような連想配列が返って来る. %info_card = ( 'accepted' , 'by nobody ...' , 'date' , '2001-04-23T09:59...' , … 'type' , 'A' , ) ※配列の「値」は &URLDecode で加工されている. common のサブルーチン ・ $info について 情報の種類は「&」で区切られている 情報の 項目 と 内容 は「:」で区切られている. foreach で各種の情報にわけ, (普通に gate-ip-show を使うと1行ごとに表示される内容) 項目を $key に 内容を $value に入れる. ・ $key = &URLDecode($key); $value = &URLDecode($value); &URLDecode($value) 結果 → $value の %[0-9A-Fa-f][0-9A-Fa-f] 部分 (正規表現をそのまま使用)を ([0-9A-Fa-f][0-9A-Fa-f])部分(16進数)を10進数 に直したものを符号無しchar値(?)でバイナリデータ にしたものに置換して返す. $x =~ s/PATTERN/REPLACEMENT/ge; → 複数の PATTERN を置換し, REPLACEMENT を 式として評価する. 置換のオプションについて → プログラミング Perl P82 hex について → プログラミング Perl P205 packについて → プログラミング Perl P224 ・ &returnAddString($key, %info_card); # $key = honey # %info_card = ( 'accepted' , 'by nobody ...' , 'date' , '2001-04-23T09:59...' , … 'type' , 'A' , ) ※配列の「値」は &URLDecode で 加工されている. 結果 → %info_card の type の値からそのホスト名のタイプが A , A & MX , MX , CNAME のいづれかであるのかを判断し, /var/named/ep.zone に書き込む書体にして スカラーとして返す 例 $addString = taiki2 IN A 133.50.136.22 taiki2 IN MX 10 taiki1.ep.sci.hokudai.ac.jp. ※ A & MX は 結局 A と MX の内容を両方(つまり2行) 書き込むだけ. 2行あるときでも,各if文で「$addString .= 〜」 となっているため, ^^ 連結されて書き込まれることになる. 参考にしているキー&値 A → ('ip' , '133.87.45.xx') MX→ ('mx' , 'xxxxx.ep.sci.hokudai.ac.jp') CNAME→('cname' , 'xxxxx.ep.sci.hokudai.ac.jp') わからないこと MXの際に頭につく「10」ってなに? □ ゾーンファイルの生成 詳しくは 上記の □新たな /var/named/ep.zone が作成されるまでのだいたいの流れ を参照のこと □ 再下部の Check〜 のサブルーチン どうも, バージョン 1.36(最新版?)あたりになった段階で 不要になったらしく, サブルーチンだけが残っているらしい. ■gate-db-to-sudoers □ これは珍しくオプションをとるスクリプトで, -h, -n, -v (ヘルプ, 非実行, ?) という効果がある. □一時書き出しファイルを $TEMPFILE= "/tmp/sudoers$$" とする. □正規の sudoers ファイルを $SUDOERSFILE = "$ETCDIR/sudoers" とする. □ホストごとにルート権限を持てるユーザを選別する.   ◆ $wheel = &HostOption('wheel') → $wheel = epwww を返す (www) → $wheel = epmail を返す (mail) → $wheel = epdns を返す (yellow,blue) → $wheel = epnews を返す (white) (無論これは専攻サーバでの設定) ・ &HostOption('wheel') gate.conf の %DB_SHARE_HOSTS の値で 「wheel:」以降 にあるものを返す. なお, 値に wheel が無いホストは wheel (=$WHEELUSER) が返る. わからないこと サブルーチン内の return について サブルーチン内に return が2つある場合, どちらかが実行された段階で, そのサブルーチン自体が 終了するのか? → return でサブルーチンは終了される. (テストスクリプトを書いて確認した.) □ 現在ある /etc/sudoers から内容を取り出し, 一部を @oldSudoers に代入する. 「#」「root」「%」が行頭にあるものは全て無視し, それ以外のものを 一行を配列の一要素として代入する. 「#」 → コメント行 「root」→ rootの行(後で生成) 何のため? 「%」 → グループにユーザに関する行 つまり, 残るのは個人ユーザに関する情報のみ (個人ユーザ情報の追加, 削除は手動で行う必要がある.) □ 一時書き出しファイルを open ・$handle = &openForWriting($TEMPFILE); → 上記参照 □ コメントと, root の文を一時保存ファイルに書き出す. □ グループユーザについて書き出し (個人ユーザについては一切書き出さない) ただし, $wheel と同じ名前のグループユーザだけは特別に扱う. 例: $wheel = epwww の時 epwww と epmail というグループユーザがあったとすると, %epwww ALL=(ALL) ALL %epmail ALL=(epmail) ALL と書き出されることになる. □ 万が一 $wheel と同じ名前のグループユーザが stable 領域に無かった場合, 強制的に $wheel というグループユーザにルート権限を与える一行を 書き加える. (こうしないと, 万が一の時にPCのルート権限をもつユーザが いなくなってしまう. ) ・ getgrnam($wheel) → $wheel のグループIDを返す. □ 現在の sudoers を sudoers.bk として保存し, いままでに作成した一時保存ファイルの内容を sudoers に上書きする. ・ 条件 オプション -n がコマンドの前についていた場合, 実行しない. わからないこと オプション -v が付いた際のことだが, 何をしたいのかわからない. コマンド visudo を起動しているようにも見えるのだが, 試しに -v オプションをつけて起動してみても, 実行されないだけで何が起こっているのか不明. ■ gate-make-home □ /etc/passwd から情報を得て, それぞれのユーザについての UID, GID, ホームディレクトリの位置 を連想配列 %UID, %GID, %HOME に代入する. ・ デバッグ時の話 (本気モードで無い時) デバッグモードの時は %HOME (本来は /home/username)を /HOME/username にすり替えておく. ^^^^ □ stable 領域からユーザ情報を取り出し, そのユーザの「type」を 連想配列 %USER_TYPE に代入する. □ QUOTA が使用できるのか確認する. もしも, QUOTAが使用できない場合は, 各ユーザにQUOTAを かけない. □ 自機ホスト名を調べる → 実は現在のスクリプトでは使用されてなかったり. □ $DOT_FILES (= /etc/skel/)以下にあるドットファイルの一覧を得て, ファイル名を @DotList に代入していく ◆ &getDotFileList($DOT_FILES) → /etc/skel/ ($DOT_FILES) 内のドットファイル名 (「..」やバックアップファイル(最後に「~」がついているもの) 以外) を配列 (@dotfiles)にして返す. ・ opendir(DIR, $dir) # $dir = /etc/skel → open 関数のディレクトリ版. この DIRという ディレクトリハンドルを以下の readdir 関数 で使用する. ・ readdir(DIR) → そのディレクトリハンドルにあるファイル名を返す. なお, 値を返す際に, 返す先がスカラー変数か配列かで 返す値が異なる. スカラー変数ならばファイル名を始めの方から順々に返し, 配列ならば, ファイル名を全ていっぺんにその配列に返す. ・if($entry =~ /^\.[^\.\s]\S*[^~]$/){ ... } 正規表現 ・行頭が「.」で, ・2文字目が「.」や空白でなく, ・ファイルの最後に「~」が付いていない ファイルのみを読み出す. □ ホームディレクトリ作成 foreach 関数で %UID のキー(ユーザ名)を取り出して, それぞれのユーザについて判定して, その結果に基づいて処理を行う. ◆ システムユーザ, stable 領域に無いユーザについて 何も行わない. ◆ 既にホームディレクトリのあるユーザについて ◇ 個人ユーザの場合 何もしない ◇ 法人ユーザ(グループユーザ)の場合 `gate-make-dot-qmail $user` コマンドで .qmail-member ファイルに グループユーザのメンバーが書き直される. このファイルにより, そのグループユーザへのメールは グループユーザのメンバーに転送される. ◆ ホームディレクトリが無いユーザについて ◇ ディレクトリの作成とそのディレクトリの所有者の設定 perl 内部の関数である mkdir, chown を使用して ディレクトリの作成と所有者の設定を行う. ◇ /etc/skel/ に存在するドットファイルをホームディレクトリに コピーし, 所有者をそのユーザにする. ◇ gate-make-dot-qmail を使用し, .qmail にユーザの連絡先 メールアドレスを書き込む. (連絡先アドレスが無い場合は 何も書き込まない.) ◇ QUOTAが使用できる場合には, QUOTAの設定を行う. ■ gate-remove-home □ defunct 領域にあるユーザのアドレスを読み込む ◆ &getDefunctUsers → 内部で &getUsersByDirectory($DB_DEFUNCT) が動いている. → /home/gate/userdb/defunct/ 以下のファイル名(つまりユーザ名)を 取り出す. □ defunct 領域にユーザ名があり, かつホームディレクトリが存在するものは 「rm -r」 コマンドでホームディレクトリを削除する. ■ gate-make-dot-qmail □ 引数の確認 このスクリプトは $ gate-make-dot-qmail username として使用する. (実際には gate-make-home の内部から起動される) このスクリプトは引数を1つしか取らないため, 2つ以上の引数を与えた場合は エラーメッセージを残し, 終了する. □ サブルーチン readCard でユーザのデータベースを取得 取得された情報は %field に代入される. (readCard は便利なサブルーチンで, ユーザ名さえ引数に取れば, それが stable, pending, defunct のどこにあっても 探し出してきてくれる.) □ /etc/passwd から, ユーザのUID, GID, ホームディレクトリの位置を 取得し,それぞれ %UID, %GID, %HOME_DIRECTORY に代入する. □ ホームディレクトリに .qmail が無い場合は .qmail を作成する. 個人ユーザと法人ユーザは別々に処理する. 判別は %field の type 欄を参照する. ◆ 個人ユーザの場合 1. ホームディレクトリに .qmail があるかどうか確認する. ・ &isaQmail($user) → $user のホームディレクトリに .qmail があれば 真, 無ければ偽が返る. 2. ファイルにコメントとユーザデータベースの「email」欄 にあるメールアドレスを ~/.qmail に直接書き込む. ◆ 法人ユーザの場合 解説(グループユーザ epnetfan の場合) .qmail に &epnetfan-member と書いてあると, .qmail-member を読みにいく. そして, .qmail-member の中身に書いてあるユーザにメール が転送される. よって, .qmail は一度作成したら変更はせず, .qmail-member の内容を変更するようにしてある. ※gate-make-dot-qmailの起動するタイミング※ gate-make-dot-qmail は gate-make-home の内部で起動される. 個人ユーザについては既にホームディレクトリが存在する場合は gate-make-dot-qmail は起動されないが, 法人ユーザ(グループユーザ)の場合はホームディレクトリの有無に かかわらず gate-make-dot-qmail が起動される. よって, 常に .qmail-member には最新のメンバーが 書き込まれている. 動作 1. ホームディレクトリに .qmail があるかどうか確認する. 2. .qmail が存在しない場合は .qmail を作成し, その中に &epnetfan-member などと書き込む. (これはもちろんグループユーザ epnetfan の場合) 3. .qmail-member にグループユーザの最新のメンバを列挙する. この作業は .qmail-member が既に存在していようがいまいが 行う. ファイルの中に書き込まれる書式は … &morikawa &uwabami &sugiyama … となっている. ◇ &Get_Member($field{'member'}) # $field{'member'} = グループユーザのメンバー. 一行にまとまっている. 区切りはスペース一文字. → 1. 行頭, 行末の空白を削除 2. 空白で分割して @Member に代入 ・ @Member=split $_ を空白で分割して @Member に代入 3. @Member を返す. 4. .qmail-member の所有者をユーザにし, パーミッションを 640 にする. □ .qmail の所有者をユーザにし, パーミッションを 640 にする. ■ gate-user-apply ☆ データベースカードの情報についてまとめ このスクリプトが起動する前に必要とされているべき情報の項目は以下の 通り. ・個人ユーザ 必須項目 name, type, status, syozoku, loginname, phone, kname, hosyounin, room 空白でも良い項目 shell, email, fax ・グループユーザ 必須項目 (空白でよい項目は無い) name, type, member, loginname, kname, hosyounin このスクリプトで作成される項目は以下のとおり ・個人ユーザ uid, password, date ・グループユーザ uid, password, date ※ accepded 項目は gate-user-accept で作成される. わからないこと shell に関するチェック項目が無いような気がするけどよいのかな? □ まずは3つのファイル(1つは設定ファイル, あと2つはperlのサブルーチン) を読み込む. 読み込むファイルは ・gate.conf ・jcode.pl ・open3.pl わからないこと open3.pl ってなんですか? □ 標準入力 (ファイル名が指定されていればそのファイル) から ユーザ情報カードを読み取る. 読み取られたユーザ情報カードはお約束どおり, %field に代入される. □ ユーザデータベース(stable, defunct, pending)に 同じログイン名がないかチェックする. 承認済み及び申請中のカードが存在すればエラーを返して終了. ◆ &pendingUserExists($username) ユーザーデータベースの保留領域(/home/gate/userdb/pending) 内に, $username と同じ名前のファイルが存在すれば 真を, 存在しなければ偽を返す. ◆ &acceptedUserExists($username) ユーザーデータベースの承認済み領域(/home/gate/userdb/stable) と, ユーザーデータベースの抹消済み領域(/home/gate/userdb/defunct) 内に, $username と同じ名前のファイルが存在すれば 真を, 存在しなければ偽を返す. ◆ &stableUserExists($username) # ここでは使用されない ユーザーデータベースの承認済み領域(/home/gate/userdb/stable) 内に, $username と同じ名前のファイルが存在すれば 真を, 存在しなければ偽を返す. □ /etc/passwd を調べて, 申請するログイン名と同じアカウントを持つ ユーザが既に存在していないか調べる. なお, 既にユーザデータベースカードは調査済みなので, アカウントが存在するということは gateシステムの管理していない ユーザが存在することになる. よってその場合は, 管理人に連絡するようにコメントを 返し, 終了する. ◆ getpwnam($username) /etc/passwd に $username が存在する場合は真を, しない場合は偽を返す. (本当は, passwd ファイル内の9つの要素を返すのに使われる.) □ $username と同じグループユーザがいないか調べる. この場合も, もしそのグループユーザが存在する場合は 管理人に連絡するようにコメントを返し, 終了する. ◆ getgrnam($username) $username というグループユーザが存在する場合は真を, しない場合は偽を返す. □ 取得したユーザカード情報(%field)がちゃんとした書式に なっているのか確認する. ◆ &checkField(%field); ◇ %Setumei というハッシュが与えられる. (エラーメッセージを出力する際の説明で使用する) %setumei = &FieldSetumeiHash(); → 以下のような %setumei というハッシュが与えられる. (要するに, 各項目についての説明である.) %setumei = ( "type", "登録種別", "accepted", "承認日時", "date", "最終更新日", : : : : "place", "設置場所", "cname", "mx", "note", "備考", ); ◇ カードの種別 (typeで判別) によって, 確認する項目が異なるため その場合分けを行う. 場合分けにより, 確認する項目を @trivial に代入する. ・type が person (個人ユーザ)の場合 @trivial = ("kname","name","phone","syozoku","room","status") なお, @trivial = qw(kname name phone syozoku room status); とした場合には, 上記の @trivial と同じになる. (「qw」は空白を区切りとする.) ・type が incorpration(法人ユーザ) の場合 @trivial = ("kname","name") ・type が存在しない場合, または type が person でも incorporation でも無い場合 エラーを出して終了 ◇ @trivial の項目を %field のキーとして使用し, 値が空欄でないか調べる. もし空欄だった場合, その項目を指定するように指示する コメントを出力して終了する. ◇ 上記の確認と同時に, 項目の中身が1文字の場合も 「おかしくない?」と出力して終了. ・ length($field{$fieldname}) → $field{$fieldname} の文字数を返す. ◇ ログイン名が8文字以上ならエラー ◇ ログイン名がハイフン, または数字で始まったらエラー → わからんこと エラーメッセージから 「1文字目は英小文字でなければならない」と したいのだろうが, 残念ながらこの行だけ見ると その役割を果たしていない. 結局この後の「ログイン名にハイフンを使用するか否か」 の部分で代わりにやってくれている. ◇ ユーザ名にハイフンをつけることを許可するかどうか gate.conf の $USE_HYPHEN_NAME を 1(許可)または 0(不許可) とすることで設定できる. ここで, それが反映される. ◇ hoshounin 項目のユーザが stable 領域に存在しなければ エラー (hoshounin が gate である場合は例外として取り除く) ◇ 個人ユーザ, グループユーザそれぞれについて その他の項目についてのチェックを行う. ・ 個人ユーザの場合 &checkForPerson(%field) 以下, このサブルーチンでの検査項目 1. 保証人 保証人が gate であるか, または, 保証人となるユーザが保証人としての資格を 有している場合はOK. そうでない場合はエラーを返して終了. 保証人の資格については以下のサブルーチンで検査する. &isaHosyounin($field{'hosyounin'}) このサブルーチンは, 以下の2点のいずれかをユーザが 満たしていれば, そのユーザを保証人として適している とし, 真を返す. 2つの条件を両方とも満たしていない場合, 適していない とし, 偽を返す. ・ そのユーザの保証人が gate である. ・ そのユーザがグループユーザ gate に所属している. 2. 名前(ログイン名でなく, ユーザの本名) 名前に 「-」「_」「,」「.」「 」(スペース) 及び 数字, 英字(大文字, 小文字) 以外のものが 含まれていた場合は エラーを返す. わからんこと 行頭に ハイフンやアンダーバー, カンマ, ピリオドなどを 置いちゃって良いんですかね? 3. 電話番号, faxナンバー 以下のサブルーチンで phone, fax の両項目を検査 &checkPhoneNumber($field{$fieldname}) # $fieldname = phone 又は fax ・ 引数が空だった場合 phone については既に空白の場合はエラーを出して 終了するようにしてあるため, 実質的には空になる可能性のあるのは fax 項目のみ fax 項目は必須でないのでこの場合は真を返す. ・ まず, 以下の書式のいずれかでない場合はエラー +国番号-市外局番-市内局番-加入者番号 (例: +81-11-716-xxxx) 市外局番-市内局番-加入者番号 (例: 011-716-xxxx) 北大内線番号 (例: xxxx) ・ 市外局番の始めが「1」であったり, 内線番号の始めが「0」である場合はエラー 以上でエラーが出ない場合はサブルーチンは真を返す. 4. メールアドレス ・ 空の場合 許して次へ進む. ・ ある場合 メールアドレスとしての書式がちゃんとしていない 場合はエラー メールアドレスのまっとうな書式の例 xxxxx@xxx.xxx.xxxx ・ 法人ユーザ(グループユーザ)の場合 &checkMember($field{'member'}) グループユーザのメンバーの一人一人について stable 領域にいるか確認し, 一人でも存在しないユーザがいる場合は エラーを返して終了する. □ グループ・ユーザの申請の場合,その保証人がグループ・ユーザ であることは認めない. その場合はエラーを返して終了する. □ 初期パスワード(アカウント作成時に設定されているパスワード) を作成する. 個人ユーザの場合に限り, 初期パスワードを作成する. グループユーザのパスワードは「*」とする. (古いバージョンだと「!」になっている) ◆ パスワードを作成するサブルーチン &generateKariPassword(); → サブルーチン &generatePassword を呼び出す. (下記参照) だが, 他の働きを先に記す. 基本的には &generatePassword サブルーチンを呼び出すのが その働きだが, 他にも以下の2つの働きを行う. 1. srand 関数で「srand(time + $$)」とすることにより, このすぐ後に使用される rand 関数により決定する値を 決める. (つまり &generatePassword 内の最初の rand で使用される) $$ はそのスクリプトのプロセスIDなので, 次に使用される rand 関数で決まる値は, 時間・PIDによって決まる (つまり実際にはランダムではない) ことになる. 2. 実際にパスワードを生成するのは &generatePassword なのだが そのパスワードが適切なものか判定する. 以下の条件を満たすものはパスワードとして不適切と見なされ, もう一度 &generatePassword でパスワード生成することになる. ・文字列の全てが英字, もしくは数字が1文字で残りが英字の場合 例 iKdXa8pW ・最後の文字が記号で, 且つ記号を合計3文字以上含む場合 例 9E (存在しない場合は 3. へ) 最長で20秒間, そのファイルが消滅するのを待つ. もしも 20秒間経ってもそのファイルが消滅しない場合は 結局3. へ進む. つまり, 他のスクリプトが動いている場合はこのファイルの 存在から, ロックをかけられるということ. ただし, 20秒を過ぎてなおスクリプトが動作しているのは 明らかにおかしいので, その場合はこのロックのファイルは なんらかのエラーと考えて上書きしてしまう. (上書き動作については次の項目で) わからないこと 20秒が経過した時点で, while 関数から last 関数で抜ける はずなのだが, 「break」という関数が使われている. (これはシェルスクリプトの関数らしい) 手元の計算機で試してみたところ, この部分で 止まってしまった. 3. /tmp/lock-gate-user-apply ファイルを作成する. つまり, 他のスクリプトに対してロックをかける. なお, ファイルの中身にはプログラムのPIDと ロックをかけた時間が記述される. 4. グローバル変数 $lockFile (ロックのために生成したファイルの名前)を返す. これはロックを外す時に使用される. ◆ ロックを解除するサブルーチン (これが使用されるのはいくつかの作業が終わってからだが) &unlock(); → $lockFile があるならば, これを削除する. つまり, ロックを外す. □ date フィールドの値を サブルーチン gmt_date から生成 □ uid フィールドをサブルーチン newUID から作成 ◆ いまだ使用されたことのないUIDを返すサブルーチン &newUID() → いままで, 一度でもgateシステムに登録されたことのある ユーザのUIDをはぶいた, もっとも若いUIDの数値を返す. 1. 全てのユーザデータベースのユーザ名を取り出す. ・ &getAllUsers → 内部で &getUsersByDirectory を作動させ, stable, pending, defunct の全ての領域のユーザ名を 配列にして返す. 2. &readCard を使用して取り出された全てのユーザ名に対する UID を取り出し, %uidTable にUIDをキー, ユーザ名を値として 代入する. 3. &normalUserRange を使用し, ユーザ領域のUIDの範囲を取り出し, $min, $max に代入する. ・ &normalUserRange → gate.confの $MIN_NORMAL_UID, $MAX_NORMAL_UID を返す. 4. for 関数を使用し, $min から $max までの UIDで使用されていない ものを探し, そのUIDを返す. もしも, $max すら使用されていた場合は「不定義」と返す. ※つまるところ※ 結局, 上記のような方法でUIDを探しているので, 新規ユーザは順序良く新しい番号のUIDを取得することになる. 既に廃棄されたユーザもいるが, このサブルーチンでは pending 領域のユーザについても読み込んでいるため, 旧ユーザのUIDを新規ユーザが使用することはない. □ いままでに作成したユーザデータベースカードを pending 領域に書き出す. ◆ 連想配列になっている情報をデータベースカード形式(userdb, ipdb 以下のファイルの形式) にしてファイルに書き出すサブルーチン &writeCardStream("OUTFILE", %field); → ファイルハンドル OUTFILE に %field の情報を データベースカード形式にして書き出す. データベースカード形式の例 name: Mogera Mogora type: person uid: 1999 : loginname: mogemoge room: 〒064-0810 北海道札幌市北区北6条西2丁目 date: 2001-04-13T14:20:34+0000 fax: □ かけていたロックを unlock サブルーチンではずす. □ 保証人に承認を促す email を送信する. 申請書の email: フィールドの宛先 (あれば) に 登録申請が受理された旨の email を送信する. なお, gate-user-applyでは, 保証人へのメールは " hosyonin@ep.sei.hokudai.ac.jp " に向かって送られる. ※ honsyonin ← 保証人のユーザ名を当てはめる. gate-user-apply でのメール送信は &openMail, &mailForm, &closeMail の3つのサブルーチンを 利用して行う. &openMail, &closeMail に関しては gate-db-to-shadow に 書いてあるのでそちらを参照のこと. ◆ gate-user-apply におけるメールの本文を書き出すサブルーチン &mailForm(%field) → 保証人に承認を促す内容をメール本文 ( /tmp/gatemail.$$ ($openMail_file) ) に書き足す. その際に, ユーザデータベースの一部も書き出し, (そのデータベース情報は %field から受け取る) 保証人(及び, 申請者)に通知する. ※組み込み関数のように振舞う printMailについて※ このサブルーチンの内部には gate-db-to-shadow 内で使用された &printMail が組み込み関数のように printMail とだけ かいて(つまり「&」を付けずに) 使用されている. 動作は &printMail と変わらない. □ 個人ユーザの登録の場合は, 仮パスワードを出力(ブラウザからの登録 申請の場合はブラウザに出力) して, 申請者に通知する. なお, 豊田さんがそういう性格なのか, パスワードに関して しつこいぐらいしっかり教えてくれる. ◆ パスワードの一文字一文字について解説する親切な(?)サブルーチン. &yomiString($kariPassword) 1. &asciiTable を呼び出し, 文字と解説を %ASCIITABLE に代入 する. (文字がキー, 解説が値) ・ &asciiTable → 上記の説明どおりのサブルーチン. ・ uc($char) → $char が英字の小文字だった場合, その大文字を 返す. 2. &ASCIITABLE のキーにパスワードの一文字一文字を代入する ことで, 解説を引き出し, 8文字分の解説ができたら, それを一つの変数にして返す. ■ gate-user-apply.cgi □ 三種類のファイルを require 設定ファイル … /etc/gate.conf ライブラリ … jcode.pl , open3.pl ・ open3.pl open の機能を拡張したライブラリで, 標準入出力とエラー出力の 3 種類を同時に扱う事ができる. - 使い方 $pid = &open3($WRITE, $READ, $ERR, "$BINDIR/gate-user-apply"); この後, ファイルハンドル $WRITE に何らかの引数を渡すと, 4 つめの要素であるプログラムに引数が渡される. その後, $READ を読み出すと, プログラムからの標準出力を 得る事が出来る. ※ $ERR はエラー出力である. なお, これを省略すると, $ERR に出力されるべき値は $READ に渡される. 参考文献 「プログラミング Perl」P524, 525 □ Cookie の情報を取得 Cookie の情報を %card に取得 取得情報は以下のもの (つまりはフォームに書き込むもの) 内容 キー ・ 希望ログイン名 loginname ・ 名前(日本語) kname ・ 名前(アルファベット) name ・ 電話番号 phone ・ ファクシミリ番号 fax ・ 所属 shozoku ・ 住所 room ・ 保証人ログイン名 hosyounin ・ メールアドレス email ・ 利用区分 status ・ 希望ログインシェル shell □ @neededFields に, 書き込んでもらうべき内容を羅列 □ %card の キー 'type' に "person" を代入 これが, gate-group-apply.cgi だと, "incorpration" を代入する. ※ スクリプトの順序ではここですぐに入力データを読み込み, ※ ※ 内部コマンド gate-user-apply に引数を渡して結果を得, ※ ※ 結果 を出力するが, ここではさきに登録フォームを出力する ※ ※ 方から先に見ていく ※ □ Cookie にデータを書き込む(らしい) ここらへん詳細不明 □ &printHtmlOpening にて HTML の始めの部分を書き出す. (「ユーザ登録申請のページ」の部分まで書き出す.) □ &printTorokuForm にて登録フォームを書き出す. ※これが表示される内容のメインの部分となる. ◆ table タグを書き出す. ◆ &FieldSetumeiHash にてそれぞれの項目(loginname や phone) をキーとした %Setumei に値(希望ログイン名, 電話番号) を得る. ◆ &printTextField にて文字列を入力するフィールドを作成. 書き出すフィールドは @neededFields から呼び出す. ◆ &printRadioButton にてラジオボタンにて選択してもらう フィールドを作成. ◆ table タグを括る. □ &printHtmlClosing で HTML の終了部分を書き出し, HTMLファイルを完結させる. ※ 以下は, 「submit」ボタンを押した時の動作である. ※ ※ Cookie を呼び出した後の挙動からスタートする ※ ※ なお, 上記の HTMLやフォームの書き出し部分は重複する ※ □ &getCGIdata で 「submit」ボタンで送られてきたデータ (URLエンコーディングされている)を 連想配列 %cgi_card ◆ &getCGIdata の中身 1. 文字コードを変換するため, jcode.pl を呼び出す. 2. URLエンコーディングされているデータを $alldata に代入 3. 英数字以外は 16進数で表示されているため (URLエンコーディングされているため) それを &URLDecode で元の文字に戻す. 4. jcode.pl で文字コードを euc にする. 5. キーと値を %card に代入する. 6. %card を返す. □ &purifyPathEnvironment で PATH 環境変数に / で始まるディレクトリ だけを残す. (なんのために行っているのかは不明) □ &open3 を使用して gate-user-apply に引数を渡し, gate-user-apply を起動する. このスクリプトでは $pid = &open3($WRITE, $READ, '', "$BINDIR/gate-user-apply"); となっているため, 引数を書き出すファイルハンドルを $WRITE , スクリプトから返される出力を受け取るファイルハンドルを $READ としている. (エラーメッセージも $READ に書き出される.) ※ なお, gate-user-apply にまっとうな引数を渡し, 起動させた時点で userdb/pending にユーザデータベースカードは書き出されるため, $READ などからデータを読み取らなくとも登録は完了してしまう. ちなみに, $pid には 子プロセス ( gate-user-apply ) のプロセスIDが 代入される. □ waitpid で gate-user-apply の終了ステータスを得る. → gate-user-apply が正常に終了し, データベースに ユーザの情報が書き込まれた場合は $exitcode = 0 書き込んだ情報にミスがあり, スクリプトがエラーを返して 終了している場合は $exitcode = 255 --解説-- 終了ステータスは $? に代入される. スクリプトが正常に終了した時は $? に 0 が返される. (gate のスクリプトでは最後に exit 0; として明示的に 0 を返している) スクリプトが正常に終了しなかった時 (代表的には die などでエラーを吐いて終了した際) は $? に 0 以外が代入される. 例えば, gate-user-apply では, 入力フォーマットの書式が正しくない 場合は die "エラーメッセージ"; としてエラーメッセージを返して スクリプトを終了する. この場合には $? に 65280 (2進数だと 1111111100000000) を返す. この $? を利用して, スクリプトがどのように終了したか 調べている. $exitcode = (($? >> 8) & 255); (「$? >> 8」では, 例えば $? = 65280 (2進数だと 1111111100000000) ならば, $? >> 8 = 255 (2進数だと 11111111) となる ) (「&」これは論理積をあらわす. 詳しくは上記) もしも, スクリプトが正常終了ならば $exitcode = 0 となる. それ以外ならば $exitcode /= 0 となる. (例えば, die でエラーが返された場合は $exitcode = 255 となる) --余談-- この $? はスクリプト内で使えるだけでなく, 普通にシェル上でも 使用することが出来る. 以下のスクリプトを起動してみよう $ /usr/local/bin/gate-user-apply test.txt (空ファイル) エラーメッセージが返るはずである. ここで, 環境変数 $? を呼び出す. $ echo $? 255 ← 終了ステータスが返る. ※ なお, この $? は厳密にはスクリプト内の $? とは異なり, $? >> 8 という処理が既になされているものである. □ Cookie にデータを書き込む(らしい) 同上 □ &printHtmlOpening にて HTML の始めの部分を書き出す. 同上 □ gate-user-apply の処理結果を表示する. 1. $exitcode が 0 かどうかで成功か失敗かを判別し, それを表示する. 2. gate-user-apply から返された文字列を &HTMLEscape でフィルタリング(?)して「<」や「>」といった文字列を 「<」や「>」など, HTMLで表現できるように変換する. 3. 上記でフィルタリング(?)した文字列を書き出す. (PRE タグでくくるため, 改行などに BR タグを入れてはいない.) 4. コメントアウトしてあるが, $exitcode や $pid の値も 出力する. (送信した情報の一覧も出力している) □ &printTorokuForm にて登録フォームを書き出すす. 同上 □ &printHtmlClosing で HTML の終了部分を書き出す. 同上 ■ gate-group-apply.cgi □ gate.conf, jcode.pl, open3.pl を読み込む □ Cookie を読み込む 読み込んだデータを %card に代入 <-- 以下 submit ボタンを押した際の動作 --> □ &getCGIData によって submit で送られてきたデータを受け取り, %cgi_card に代入し, それを %card に代入 □ gate 登録用パスワード $card{'token'} を削除し, gate-user-apply に送らないようにする. ※ 実際には, 余計な値を gate-user-apply に与えても 問題なく動作する(もちろん必要な値は書き込まれている必要があるが) ので, パスワードを送っても動作はする. ただし, セキュリティの問題から必要の無いプロセスに パスワードを送るのは問題があるため, 削除しておく. □ 登録処理 &TorokuSyori($token) を使用し, 以下の作業を行う. 1. $token に代入されている gate 登録パスワードの照合 2. %card を gate-user-apply コマンドに渡し, データベースカードを 作成 3. gate-user-apply の終了ステータスを $exitcode に返し, 成功したか, 失敗したかの判別を行えるようにする. ◆ &TorokuSyori の内部 1. &gatePasswordCheck にグループユーザの保証人 (つまりグループユーザを申請するユーザ)のアカウント名と 入力した gate パスワードを渡し, そのパスワードが正しいものであるか判別する. 正しければ真が, 間違っていれば偽が返る. 2. 上記の &gatePasswordCheck にて偽が返った場合は 終了ステータス 254 をメインのスクリプトに返す. そうでなかった場合は下の動作を行う. 3. &purifyPathEnvironment にてパスを / のみにする. 4. open3 を使って, gate-user-apply に %card を渡す. (%card はグローバル変数なので, 参照渡しではない) 5. gate-user-apply から返されたメッセージを グローバル変数 @result に代入し, それとは別に終了ステータスをメインスクリプトに返す. ◇ &gatePasswordCheck の内部 渡される変数は $card{'hosyounin'} と $token 1. グローバル変数 $result に "パスワードが違います." と代入 2. 保証人のユーザ名を &homedir に代入して ユーザのホームディレクトリを探索し, $homedir に代入 この $homedir にある .gate というファイルを パスワードファイルと認識する. 3. パスワードファイルが無い場合は 偽を返す. 4. パスワードファイルを読み込めない場合は $result に "読み取り用に開けません." と書き出した後, 偽を返す. 5. パスワードファイルを読み込めた場合は この中のパスワード部分を取り出し, $cryptedtoken に代入 6. この $cryptedtoken の始め2文字を取り出して $salt に代入. この最初の2文字は暗号化に使用される "塩" と呼ばれ, この塩を変えることで, 同じパスワードも違う文字列になる. 7. 最後に, $token (CGI から読み込まれたパスワード) を 先ほどの $salt で暗号化したものと $cryptedtoken が等しいかどうかを判定し, 等しければ真を, 異なれば偽を返す. □ パスワードの復旧 (2002/03/20 に削除) 先ほど削除した %card{'token'} を復帰させ, Cookie に 書き出せるようにする. → 生パスワードを, 外部から読み取れる Cookie に書き出すのは 危険と判断したため, この部分は削除した. <-- ここまでが submit ボタンを押した際の動作 --> <-- 以下は常に働く動作 --> □ &printSetCookieHeader にて Cookie を書き出す. □ &printHtmlOpening にて HTML の始めの部分を書き出す. <-- ここまでが 常に働く動作 --> <-- 以下は submit ボタンを押した際の動作 --> □ $exitcode の値から, gate-user-apply が成功したのか エラーを返したのか判別して, それを出力する. □ グローバル変数 @result をメッセージとして出力 <-- ここまでが submit ボタンを押した際の動作 --> <-- 以下は常に働く動作 --> □ &printTorokuForm で登録フォームを表示する. ただし, submit ボタンを押した時で, 且つ, $exitcode が 0 (つまり, スクリプトが正常に終了した時) にはこのフォームは表示しない. □ &printHtmlClosing で HTMLの終了部分を書く. ■ gate-user-renew ユーザデータベース変更用スクリプト (ただし, コマンドラインから変更する場合は root か 保証人しか 行うことが出来ない.) □ データベース情報を読み込む. データベースを読み込む方法には 2種類ある. 1. データベース書式で書き込まれているファイルを 引数として gate-user-renew に渡す. 2. データベースの要素を一つ一つ標準入力で gate-user-renew に渡していく. ※ CGI である gate-user-renew.cgi から gate-user-renew を 起動する場合は後者の方法を取る. (open3.pl を使用し, ファイルハンドル $WRITE から与える.) <-- 以下は サブルーチン &main の内容であるが, むしろこれが --> <-- このスクリプトの本体なのでインデントしない --> □ データベースを読み取り %field に代入 □ 以下のいくつかの項目についてチェック 1. loginname にログイン名を書き込んであるかどうか. 2. loginname に書き込まれたアカウント名が stable に存在するか 3. gate-user-renew を起動したユーザが登録内容変更を行う権限を 有するユーザかどうか これらの3つのチェックのいづれかでも引っかかった場合は, エラーメッセージと終了ステータス(0 以外)を返してスクリプトを 終了する. ◆ &iamAuthorizedUser ユーザ名 と データベースフィールドの保証人のアカウント名を 受け取り, このスクリプト(gate-user-renew) を起動しているユーザが この登録変更を行う権限をもつか判定する. 権限を有する場合は真を, 有しない場合は偽を返す. 1. このプロセスの実UIDが 0 の時 (つまり, gate-user-renew がルートにより実行されている時) は権限を有すると見なす. なお実UIDは $< にて与えられる. 2. このプロセスを実行しているユーザが $CGIUSER (CGI を実行するユーザで gate.conf にて指定されている) の場合は権限を有すると見なす. gate-user-renew.cgi にて起動された場合に, プロセスの実UID が $CGIUSER のものとなる. ※ つまりこのチェックをしないと, CGIからの登録が出来なくなる. 3. このプロセスを実行しているユーザが 保証人権限を有するユーザであれば (&isaHosyounin にてチェック) 権限を有するものと見なす. ※ つまり, 保証人は全てのユーザの登録情報を 変更できてしまうということである. 4. このプロセスを実行しているユーザが 保証人のユーザアカウント名と同じ場合は 権限を有すると見なす. ※ これは, グループユーザの変更の際に必要な措置である. □ &checkField で %field の値の書式, 及びその内容のチェックを 行う. &checkField は正しくない項目を発見した段階でその旨をエラーメッセージ に返し, スクリプトを終了させる. □ -c オプションをつけて, gate-user-renew を起動していた場合は ここで終了 (終了ステータスは 0) □ %field に無く(つまり gate-user-renew が受け取った データベース情報に無く), 現在のデータベースカードにある情報を %field に書き出す. ※ &checkField にて %field の中身は確認されているため, この部分はほとんど意味が無い(?) □ $field{'passwd'} の部分には, 現在のデータベースカードのものが 書き出される □ $field{'hosyonin'} の部分を gate ユーザにしようとした場合は それができないことを出力する. ※ ただし, 終了はせず, 変更自体は行われる. □ $field{'uid'} の部分には, 現在のデータベースカードのものが 書き出される □ &gmt_date で時間を取得し $field{'date'} に代入する. ※ これで最終更新日時を知ることが出来る. □ ここまで作成した %field を stable 領域以下に書き出す. □ -t オプションをつけていた場合は, ここで終了 (メールを流さない) □ 通知メール製作・送信サブルーチン &openMail, &mailForm, &closeMail を使用し, 保証人とユーザに通知のメールを送る. ※ この3つのサブルーチンのうち, &openMail, &closeMail は gate-common.pl に記述された, 全スクリプト共通サブルーチンだが, &mailForm だけは, それぞれのスクリプトの内部にサブルーチンを 持っており, 別々の挙動をする. (基本は一緒だけど) □ gate ポートを叩いて gate-daily を起動させる. ■ gate-user-renew.cgi □ まずは, &syokiGamen で以下の 3 つの項目を入力するフォームを出力 1. 変更したいアカウント名 2. 変更を行うユーザ 3. gate 登録パスワード 出力後, gate-user-renew.cgi は一旦終了する. この後, submit ボタンを押すと, 再び gate-user-renew.cgi が起動する. <-- 以下は submit ボタンを押した際の挙動である. --> □ &getCGIData で CGIから入力されたデータを %card に代入する. □ %card の内, パスワードとパスワードを保有しているユーザのアカウント名 を &gatePasswordCheck に渡し, パスワードが正しいかどうかチェックする 問題がある場合は, $result (大抵は, "パスワードが違います"が 代入されている) が &error に渡され, 終了する. (終了ステータスは 0 にしてある.) ◆ &error 1. &printHtmlOpening を起動し, HTMLの始めの部分を書き出す. なお, ここでは 渡す要素が2つあり, 2つめに 色 "#DDAAAA"(赤系の色) が渡され, 表示される HTML の背景にこの色が使われる. 2. $result に代入されているエラーメッセージを表示する. 3. &printHtmlClosing でHTMLを閉じる. <-- 以下は 登録内容更新/変更フォームで submit ボタンを 押した際の挙動である. --> ※ 始めの, 変更するアカウント名, パスワード, 変更を行うユーザのアカウント名を入力するフォームで submit ボタンを 押した時と, 変更内容自体を書き込むフォームで submit ボタンを押した時との 区別は, $card{'date'} が真か偽かで行う. これが真の場合は 後者のフォームで submit ボタンが押されたと 判断される. なお, この要素は後者のフォームで submit ボタンを押した際に 作成され, &getCGIdate にて %card に保存される. □ %card のうち, パスワードの要素と, それを保有するユーザアカウントの 要素が削除される. □ &open3 を使用し, gate-user-renew を起動する. @result に結果のメッセージが代入され, $exitcode に正否が代入される. <-- ここまでが 登録内容更新/変更フォームで submit ボタンを 押した際の挙動である. --> □ &printHtmlOpening <-- 以下は 登録内容更新/変更フォームで submit ボタンを 押した際の挙動である. --> □ $exitcode から gate-user-renew が成功したか判別し 正否とメッセージを返す. <-- ここまでが 登録内容更新/変更フォームで submit ボタンを 押した際の挙動である. --> <-- 以下は 登録内容更新/変更フォームで submit ボタンを 押す前の挙動である. (ボタンを押した際には, 以下の部分は動作しない) この挙動により, 現在のデータベースがフォームに書き出される --> □ gate-user-show に -c オプションをつけ, $loginname (変更されるアカウント) を渡し, URLエンコードされている データベースを呼び出す. そのデータを &parseCookie にて %card に渡す. □ 今回変更を申請したユーザがそのアカウントを更新/変更できるのか チェックする. 以下のどれにも当てはまらない場合には更新/変更の権限を有さない. 1. 変更申請したユーザのアカウントが変更を行うアカウントと同じ 2. 変更申請したユーザが変更を行うアカウントの保証人 3. 変更申請したユーザが gate ユーザ (gate グループではなく) <-- ここまでが 登録内容更新/変更フォームで submit ボタンを 押さなかった時の挙動である. --> □ &printTorokuForm にて登録フォームが表示される. ※ 他の printTorkuform と異なるところ. 以下の項目が固定されている. ・ 変更するアカウント名 ・ type ・ 変更を申請するユーザのアカウント名 これは, gate-user-renew には必要ないが, パスワードチェックに使用される. ・ date 項目 &gmt_date で作成される. 上記のように, 「更新/変更フォーム」で submit ボタンを 押したかどうかを判定するのに使用する. ただし, この値がそのままデータベースに使用されることは無い (gate-user-renew の方でも同様に &gmt_date でこの値を 作成し, そちらがデータベースに書き込まれる.) □ &printHtmlClosing にてHTMLを閉じる.