#!/usr/bin/perl -U
$config = "./wam.conf";
$gconfig = "./group.conf";
$tmp_index = "./index.tmp";
$tmp_passwd = "./passwd.tmp";
$tmp_shadow = "./shadow.tmp";
$tmp_group = "./group.tmp";
$tmp_gshadow = "./gshadow.tmp";
@referers = ('jls.idv.tw','61.64.116.164');
##############################################################################
$itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
$HOST=`/bin/hostname`;
$HOST=~ s/\n//g;
@DOMAIN = split(/./,$HOST);
$ii = 0;
foreach $DN (@DOMAIN) {
$DOMAIN[$ii]=".$DOMAIN[$ii]" if ($DN ne '');
$ii++;
}
$PORT="12000";
$| = 1;
$today = int(time / 86400);
$err = 0;
use MD5;
sub to64 {
my ($v, $n) = @_;
my $ret = '';
while (--$n >= 0) {
$ret .= substr($itoa64, $v & 0x3f, 1);
$v >>= 6;
}
$ret;
}
sub rnd64 {
my $ret = '';
my $n = 8, $i;
while (--$n >= 0) {
$i = rand;
$ret .= substr($itoa64, int($i*64), 1);
}
$ret;
}
sub unix_md5_crypt {
my($pw, $salt) = @_;
my $passwd;
my $Magic = '$1$';
$salt =~ s/^\Q$Magic//;
$salt =~ s/^(.*)\$.*$/$1/;
$salt = substr($salt, 0, 8);
$ctx = new MD5;
$ctx->add($pw);
$ctx->add($Magic);
$ctx->add($salt);
my ($final) = new MD5;
$final->add($pw);
$final->add($salt);
$final->add($pw);
$final = $final->digest;
for ($pl = length($pw); $pl > 0; $pl -= 16) {
$ctx->add(substr($final, 0, $pl > 16 ? 16 : $pl));
}
for ($i = length($pw); $i; $i >>= 1) {
if ($i & 1) { $ctx->add(pack("C", 0)); }
else { $ctx->add(substr($pw, 0, 1)); }
}
$final = $ctx->digest;
for ($i = 0; $i < 1000; $i++) {
$ctx1 = new MD5;
if ($i & 1) { $ctx1->add($pw); }
else { $ctx1->add(substr($final, 0, 16)); }
if ($i % 3) { $ctx1->add($salt); }
if ($i % 7) { $ctx1->add($pw); }
if ($i & 1) { $ctx1->add(substr($final, 0, 16)); }
else { $ctx1->add($pw); }
$final = $ctx1->digest;
}
$passwd = '';
$passwd .= to64(int(unpack("C", (substr($final, 0, 1))) << 16)
| int(unpack("C", (substr($final, 6, 1))) << 8)
| int(unpack("C", (substr($final, 12, 1)))), 4);
$passwd .= to64(int(unpack("C", (substr($final, 1, 1))) << 16)
| int(unpack("C", (substr($final, 7, 1))) << 8)
| int(unpack("C", (substr($final, 13, 1)))), 4);
$passwd .= to64(int(unpack("C", (substr($final, 2, 1))) << 16)
| int(unpack("C", (substr($final, 8, 1))) << 8)
| int(unpack("C", (substr($final, 14, 1)))), 4);
$passwd .= to64(int(unpack("C", (substr($final, 3, 1))) << 16)
| int(unpack("C", (substr($final, 9, 1))) << 8)
| int(unpack("C", (substr($final, 15, 1)))), 4);
$passwd .= to64(int(unpack("C", (substr($final, 4, 1))) << 16)
| int(unpack("C", (substr($final, 10, 1))) << 8)
| int(unpack("C", (substr($final, 5, 1)))), 4);
$passwd .= to64(int(unpack("C", substr($final, 11, 1))), 2);
$final = '';
$Magic . $salt . '$' . $passwd;
}
sub check_referer {
my $check_referer = 0;
my ($uid,@uid,@addrs);
$addr = $ENV{'REMOTE_ADDR'};
$url = $ENV{'HTTP_REFERER'};
if ($url =~ m|https?://([^/]*)$DOMAIN[1]$DOMAIN[2]$DOMAIN[3]/~([\w.]+)/(.*)|i) {
$user = $2;
}
foreach $referer (@referers) {
if ($url =~ m|https?://([^/]*)$referer|i) {
$check_referer = 1;
last;
}
}
$check_referer = 1 if ($url =~ m|https?://([^/]*)$HOST|i);
@addrs = `ifconfig | grep 'inet addr:'`;
foreach $addr (@addrs) {
$addr =~ /inet addr:([\w.]*)/;
if ($url =~ m|https?://([^/]*)$1|i) {
$check_referer = 1;
last;
}
}
$check_referer = 1 if ($url eq '');
if ($check_referer ne 1) {
&head($SYSMSG{'title_system_info'});
print "
$SYSMSG{'msg_acl_warn'}";
exit 0;
}
}
sub get_form_data {
my(@parts, @pairs, $buffer, $pair, $name, $value, $bound, $getfilename, $fname, $filename, $tmp1, $tmp2, $temp, @cookies);
if($ENV{'REQUEST_METHOD'} =~ /get/i) {
return;
} else {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs=split(/&/,$buffer);
}
%DATA = ();
foreach $pair (@pairs) {
($name,$value) = split(/\=/,$pair);
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$name =~ s/~!/ ~!/g;
$name =~ s/\+/ /g;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/~!/ ~!/g;
$value =~ s/\+/ /g;
if ($DATA{$name} ne '') {
$DATA{$name} .= ",$value";
} else {
$DATA{$name} = $value;
}
}
}
sub read_conf {
return if (!(-e $config));
open (CFG, "< $config") || &err('err_cannot_open_config');
while ($line = ) {
my($name, $value) = split(/:/, $line);
$value =~ s/\n//g;
$CONFIG{$name} = $value;
}
close(CFG);
}
sub read_gconf {
return if (!(-e $gconfig));
open (GCFG, "< $gconfig") || &err('err_cannot_open_gconfig');
while ($line = ) {
my($name, $value) = split(/:/, $line);
$value =~ s/\n//g;
$GCONF{$name} = $value;
}
close(GCFG);
}
sub write_gconf {
my($grp, $home);
open(GCFG, "> $gconfig") || &err('err_cannot_open_gconfig');
foreach $grp (keys %GCONF) {
$home = $GCONF{$grp};
print GCFG "$grp:$home\n" if ($grp ne '' && $home ne '');
}
close(GCFG);
}
sub read_group {
open (GRP, "< $CONFIG{'group'}") || &err('err_cannot_open_group');
while ($line = ) {
my($gname, $ignore, $gid, $users) = split(/:/, $line);
if ($gid ne '') {
$GIDS{$gid} ++;
$GNAME{$gname} ++;
$GNMID{$gname} = $gid;
$GIDNM{$gid} = $gname;
$GIG{$gname} = $ignore;
$GUSRS{$gname} = $users;
}
}
close(GRP);
}
sub write_group {
my($gid, $grp, $gig, $gu, $gstr);
open(TMPG, "> $tmp_group") || &err('err_cannot_open_temp');
foreach $grp (keys %GNAME) {
$gid = $GNMID{$grp};
$gig = $GIG{$grp};
$gu = $GUSRS{$grp};
$gstr = join ':', $grp, $gig, $gid, $gu;
print TMPG "$gstr";
}
close(TMPG);
open(TMPG, "< $tmp_group") || &err('err_cannot_open_temp');
open (GRP, "> $CONFIG{'group'}") || &err('err_cannot_open_group');
flock GRP, $LOCK_EX;
print GRP ;
flock GRP, $LOCK_UN;
close(GRP);
close(TMPG);
unlink($tmp_group);
}
sub read_passwd {
open (PWD, "< $CONFIG{'passwd'}") || &err('err_cannot_open_passwd');
while ($line = ) {
my($uname, $ignore, $uid, $gid, $gecos, $home, $shell) = split(/:/, $line);
if ($uid ne '') {
$UIDS{$uid} ++;
$UNAME{$uname} ++;
$UNMID{$uname} = $uid;
$UIDNM{$uid} = $uname;
$UGID{$uid} = $gid;
$GECOS{$uid} = $gecos;
$HOME{$uid} = $home;
$SHELL{$uid} = $shell;
}
}
close(PWD);
}
sub write_passwd {
my($uid, $n, $gn, $g, $gec, $h, $pstr, $sh);
open(TMPP, "> $tmp_passwd") || &err('err_cannot_open_temp');
foreach $uid (sort keys %UIDS) {
$n = $UIDNM{$uid};
$g = $UGID{$uid};
$gec = $GECOS{$uid};
$h = $HOME{$uid};
$sh = $SHELL{$uid};
$pstr = join ':', $n, 'x', $uid, $g, $gec, $h, $sh;
print TMPP "$pstr";
}
close(TMPP);
open(TMPP, "< $tmp_passwd") || &err('err_cannot_open_temp');
open (PWD, "> $CONFIG{'passwd'}") || &err('err_cannot_open_passwd');
flock PWD, $LOCK_EX;
print PWD ;
flock PWD, $LOCK_UN;
close(PWD);
close(TMPP);
unlink($tmp_passwd);
}
sub read_shadow {
open (SHD, "< $CONFIG{'shadow'}") || &err('err_cannot_open_shadow');
while ($line = ) {
my($uname, $pwd, $sday, $smin, $smax, $swarn, $sinact, $sexp, $sflag) = split(/:/, $line);
if ($uname ne '') {
$PASS{$uname} = $pwd;
$SDAY{$uname} = $sday;
$SMIN{$uname} = $smin;
$SMAX{$uname} = $smax;
$SWARN{$uname} = $swarn;
$SINACT{$uname} = $sinact;
$SEXP{$uname} = $sexp;
$SFLAG{$uname} = $sflag;
}
}
close(SHD);
}
sub write_shadow {
my($uid, $usr, $mi, $ma, $w, $d, $p, $i, $e, $w, $f, $sstr);
open(TMPS, "> $tmp_shadow") || &err('err_cannot_open_temp');
foreach $uid (sort keys %UIDS) {
$usr = $UIDNM{$uid};
$p = $PASS{$usr};
$p = unix_md5_crypt($usr,&rnd64) if ($p eq "");
$d = $SDAY{$usr};
$d = $today if ($d eq "");
$mi = $SMIN{$usr};
$mi = $CONFIG{'min'} if ($mi eq "");
$ma = $SMAX{$usr};
$ma = $CONFIG{'max'} if ($ma eq "");
$w = $SWARN{$usr};
$w = $CONFIG{'pwarn'} if ($w eq "");
$i = $SINACT{$usr};
$i = $CONFIG{'inact'} if ($i eq "");
$e = $SEXP{$usr};
if ($e eq "") {
$e = $today + $CONFIG{'expire'};
$e = -1 if ($CONFIG{'expire'} < 30);
}
$f = $SFLAG{$usr};
$f = $CONFIG{'flag'}."\n" if ($f eq "");
$sstr = join ':', $usr, $p, $d, $mi, $ma, $w, $i, $e, $f;
print TMPS "$sstr";
}
close(TMPS);
open(TMPS, "< $tmp_shadow") || &err('err_cannot_open_temp');
open (SHD, "> $CONFIG{'shadow'}") || &err('err_cannot_open_shadow');
flock SHD, $LOCK_EX;
print SHD ;
flock SHD, $LOCK_UN;
close(SHD);
close(TMPS);
unlink($tmp_shadow);
}
sub get_uid {
my $i;
for ($i=500;$i<65535;$i++) {
last if (!defined($UIDS{$i}));
}
$i;
}
sub get_gid {
my $i;
for ($i=500;$i<65535;$i++) {
last if (!defined($GIDS{$i}));
}
$i;
}
sub addone {
my($usr, $grp, $pwd, $desc) = @_;
my($lvl, @lvls, $home, $gn);
&err('err_account_has_been_used') if (defined($UNAME{$usr}));
&err('err_account_is_empty') if ($usr eq '');
&err('err_group_is_empty') if ($grp eq '');
$gn = $grp;
$home = "$CONFIG{'base_dir'}/$grp" if ($CONFIG{'home_nest'} eq 'yes');
&add_grp($grp,$home) if (!defined($GNAME{$grp}));
$uid = &get_uid;
$g = $GNMID{$gn};
$h = $GCONF{$gn};
$h = '/home' if ($h eq '');
$UIDS{$uid} ++;
$UNAME{$usr} ++;
$UNMID{$usr} = $uid;
$UIDNM{$uid} = $usr;
$UGID{$uid} = $g;
$GECOS{$uid} = '';
$HOME{$uid} = ($CONFIG{'home_nest'} eq 'yes') ? "$h/$usr" : "$CONFIG{'base_dir'}/$usr";
$SHELL{$uid} = $CONFIG{'shell'}."\n";
$PASS{$usr} = unix_md5_crypt($pwd,&rnd64);
$SDAY{$usr} = $today;
$SMIN{$usr} = $CONFIG{'min'};
$SMAX{$usr} = $CONFIG{'max'};
$SWARN{$usr} = $CONFIG{'pwarn'};
$SINACT{$usr} = $CONFIG{'inact'};
$exp = $today + $CONFIG{'expire'};
$exp = -1 if ($CONFIG{'expire'} < 30);
$SEXP{$usr} = $exp;
$SFLAG{$usr} = $CONFIG{'flag'}."\n";
$sreqn{$uid} = $usr;
$sreqg{$uid} = $gn;
$sreqp{$uid} = $pwd;
$sreqt{$uid} = join ':', $usr, "x", $uid, $g, $desc, $HOME{$uid}, $SHELL{$uid};
$sreqs{$uid} = join ':', $usr, $PASS{$usr}, $SDAY{$usr}, $SMIN{$usr}, $SMAX{$usr}, $SWARN{$usr},
$SINACT{$usr}, $SEXP{$usr}, $SFLAG{$usr};
}
sub add_grp {
my($grp,$home) = @_;
my($gid);
$gid = &get_gid;
$GIDS{$gid} ++;
$GNAME{$grp} ++;
$GNMID{$grp} = $gid;
$GIDNM{$gid} = $grp;
$GIG{$grp} = "";
$GUSRS{$grp} = "\n";
$GCONF{$grp} = $home;
}
sub smb_passwd {
my($usr, $pwd) = @_;
system("(echo $pwd;echo $pwd)|$CONFIG{'smbprog'} -s -a $usr > /dev/null");
}
sub make_index {
open(IDX, "> $tmp_index") || &err('err_cannot_open_homepage_sample');
print IDX "\n";
print IDX "\n";
print IDX "\n";
print IDX "\n";
print IDX "USER$SYSMSG{'msg_homepage'}\n";
print IDX "\n";
print IDX "\n";
print IDX "\n";
print IDX "
\n";
print IDX "\n";
print IDX "\n";
print IDX "$SYSMSG{'msg_you_are'}
$SYSMSG{'msg_visited'}\n";
print IDX "$SYSMSG{'msg_my_gbook'}
\n";
print IDX "
\n";
print IDX "$SYSMSG{'msg_hi'} \n";
print IDX "
\n";
print IDX "$SYSMSG{'msg_my_email'}:USER\@HOSTNAME
\n";
print IDX "$SYSMSG{'msg_admin'}
\n";
close(IDX);
}
sub make_passwd {
my($uid, $n, $gn, $g, $d, $p, $pstr, $sstr, $l, $h, @lvls, $lvl, $line, $exp);
open(TMPP, "> $tmp_passwd") || &err('err_cannot_open_temp');
open(TMPS, "> $tmp_shadow") || &err('err_cannot_open_temp');
&write_group;
&write_gconf;
foreach $uid (sort keys %sreqn) {
print TMPP "$sreqt{$uid}";
print TMPS "$sreqs{$uid}";
}
close(TMPP);
close(TMPS);
open(TMPP, "< $tmp_passwd") || &err('err_cannot_open_temp');
open (PWD, ">> $CONFIG{'passwd'}") || &err('err_cannot_open_passwd');
flock PWD, $LOCK_EX;
print PWD ;
flock PWD, $LOCK_UN;
close(PWD);
close(TMPP);
open(TMPS, "< $tmp_shadow") || &err('err_cannot_open_temp');
open (SHD, ">> $CONFIG{'shadow'}") || &err('err_cannot_open_shadow');
flock SHD, $LOCK_EX;
print SHD ;
flock SHD, $LOCK_UN;
close(SHD);
close(TMPS);
unlink($tmp_passwd);
unlink($tmp_shadow);
foreach $uid (sort keys %sreqn) {
system("mkdir -p $HOME{$uid}");
if ($CONFIG{'add_homepage'} eq 'yes') {
system("mkdir -p $HOME{$uid}/$CONFIG{'home_dir'}");
if (-e $tmp_index) {
open(IDX, "< $tmp_index");
my @buffer = ;
close(IDX);
foreach $line (@buffer) {
$line =~ s/USER/$UIDNM{$uid}/g;
$line =~ s/HOSTNAME/$HOST/g;
$line =~ s/PORT/$ENV{'SERVER_PORT'}/g;
}
open(IDX, "> $HOME{$uid}/$CONFIG{'home_dir'}/index.htm");
print IDX @buffer;
close(IDX);
}
}
system("cp -f $CONFIG{'skel_dir'}/local.cshrc $HOME{$uid}/.cshrc") if (-e "$CONFIG{'skel_dir'}/local.cshrc");
system("cp -f $CONFIG{'skel_dir'}/local.login $HOME{$uid}/.login") if (-e "$CONFIG{'skel_dir'}/local.login");
system("cp -f $CONFIG{'skel_dir'}/local.profile $HOME{$uid}/.profile") if (-e "$CONFIG{'skel_dir'}/local.profile");
system("chown -R $uid:$UGID{$uid} $HOME{$uid}");
system ("edquota -p $CONFIG{'quota_user'} $UIDNM{$uid}") if ($CONFIG{'quota_user'} ne '');
&smb_passwd($UIDNM{$uid},$sreqp{$uid}) if ($CONFIG{'sync_smb'} eq 'yes');
}
%sreqn = ();
%sreqg = ();
%sreqp = ();
%sreqt = ();
%sreqs = ();
}
sub err {
my($errno) = @_;
$err = 1;
if ($errno eq 'err_group_is_empty') {
$errmsg = '找不到您所隸屬的群組,因此帳號無法建立,請告知電腦老師處理!';
}
if ($errno eq 'err_account_is_empty') {
$errmsg = '您的帳號尚未輸入,因此無法建立,請重新提出申請或告知電腦老師處理!';
}
if ($errno eq 'err_account_has_been_used') {
$errmsg = '您的帳號與別人重複,因此無法建立,請重新提出申請或告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_homepage_sample') {
$errmsg = '網頁範例檔無法讀取,因此無法為您建立首頁,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_temp') {
$errmsg = '無法建立暫存檔案,帳號建立失敗,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_passwd') {
$errmsg = '無法開啟系統帳號檔,帳號建立失敗,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_shadow') {
$errmsg = '無法開啟系統密碼檔,帳號建立失敗,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_group') {
$errmsg = '無法開啟系統群組檔,帳號建立失敗,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_gconfig') {
$errmsg = '無法開啟群組設定檔,帳號建立失敗,請告知電腦老師處理!';
}
if ($errno eq 'err_cannot_open_config') {
$errmsg = '無法開啟系統設定檔,帳號建立失敗,請告知電腦老師處理!';
}
print "Location: http://www.spps.tp.edu.tw/msg.asp?msg=$errmsg\n\n";
exit 0;
}
#***********************************************************************************
# MAIN
#***********************************************************************************
&check_referer;
&read_conf;
&read_shadow;
&read_passwd;
&read_gconf;
&read_group;
&get_form_data;
&addone($DATA{'account'}, $DATA{'group'}, $DATA{'passwd'}, $DATA{'name'});
&make_passwd;
print "Location: $DATA{'recall'}\n\n";