Администрилка
вот:
#!/usr/bin/perl # Copyright (C) 2001 Sergey A. Eremenko # Created for JSC Rostovtelecom # Licensed by GPL # # $Id: mailadmin v1.0.0 $ # # ИДЕЯ: # # Установить mailadmin в качестве shell для администраторов почты. # Или для тех, кто входит в группу cyrus и уже имеет нормальный shell, # достаточно запустить его. Права на исходник ставятся --x--x---, чтобы # никто не мог подсмотреть код. # # use English ; use Term::ReadLine ; use Term::ReadKey ; use Socket ; use POSIX qw/isatty/ ; use IO::Handle ; use Sys::Syslog qw(:DEFAULT setlogsock) ; use IMAP::Admin ; use Getopt::Std ; sub exec_jah_admin { my ($pid,$exit_code) ; my ($command,$username,$password) = @_ ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; if ($pid = open (F,"|-")) { F->autoflush (1) ; if (defined ($password)) { print F $password || warn "Can't print to pipe: $!\n" ; } close (F) || warn "Can't close pipe: $!\n" ; $exit_code = $? ; (0==$exit_code) || warn "$jah_admin returns $exit_code\n" ; syslog ('debug',"%s returns %d",$jah_admin,$exit_code) ; return $exit_code ; } else { warn "Can't fork: $!\n" unless defined ($pid) ; if (defined ($username)) { exec ($jah_admin,"-ZD",$jah_dbname,$command,$username) || die "Can't exec $jah_admin: $!\n" ; } else { exec ($jah_admin,"-ZD",$jah_dbname,$command) || die "Can't exec $jah_admin: $!\n" ; } } } sub help { syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; print ( "?, help - display this help\n" . "quit, exit, ^D - quit this program\n" . "ls [boxes...], list [boxes...] - list mailboxes (allow IMAP wildcards)\n" . "mk boxes..., create boxes... - create mailbox\n" . "rm boxes..., delete boxes... - delete mailbox\n" . "mv boxes..., rename boxes... - rename mailbox\n" . "lk boxes..., lock boxes... - lock mailbox\n" . "ul boxes..., unlock boxes... - unlock mailbox\n" . "ch boxes..., check boxes... - check password\n" . "pw boxes..., passwd boxes... - change password\n" . "" ) ; } sub list_mailbox { my (@names) ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; if (!defined (@_) || $#_<0) { $_[0] = "*" ; } foreach (@_) { if (!defined (@names = $imap->list ("user." . $_))) { warn ("can't list imap box user.".$_.": ".$imap->{Error}."\n") ; syslog ('info',"can't list imap box user.%s: %s",$_,$imap->{Error}) ; return ; } foreach (@names) { print $_,"\n" ; $_ =~ s/^user\.// ; &exec_jah_admin ($_) ; } } } sub create_mailbox { my $new_password,$retype_password ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; foreach (@_) { if (!$opt_j) { print "$_ New password: " ; Term::ReadKey::ReadMode 'noecho' ; $new_password = Term::ReadKey::ReadLine 0 ; chomp $new_password ; Term::ReadKey::ReadMode 'restore' ; print "\n" ; if ($new_password eq "") { warn "Password clear, skip operation\n" ; syslog ('debug','password clear') ; return ; } print "$_ Retype new password: " ; Term::ReadKey::ReadMode 'noecho' ; $retype_password = Term::ReadKey::ReadLine 0 ; chomp $retype_password ; Term::ReadKey::ReadMode 'restore' ; print "\n" ; if ($new_password ne $retype_password) { warn "Mismatch, skip operation\n" ; syslog ('debug','mismatch') ; return ; } } # create imap if ($imap->create ("user." . $_)) { warn ("can't create imap box user.".$_.": ".$imap->{Error}."\n") ; syslog ('info',"can't create imap box user.%s: %s",$_,$imap->{Error}) ; return ; } if ($imap->set_acl ("user." . $_, $imap_admin_username, "lrswipdca")) { warn ("can't set_acl imap box user.".$_.": ".$imap->{Error}."\n") ; syslog ('info',"can't set_acl imap box user.%s: %s",$_,$imap->{Error}) ; return ; } # create acl for mailadmin if (!$opt_j) { &exec_jah_admin ("-c",$_,$new_password) ; } } } sub delete_mailbox { syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; foreach (@_) { # delete imap if ($imap->delete ("user." . $_)) { warn ("can't delete imap box user.".$_.": ".$imap->{Error}."\n") ; syslog ('info',"can't delete imap box user.%s: %s",$_,$imap->{Error}) ; return ; } if (!$opt_j) { &exec_jah_admin ("-d",$_) ; } } } sub rename_mailbox { my $new_name ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; foreach (@_) { if (!$opt_j) { print "$_ New name: " ; $new_name = Term::ReadKey::ReadLine 0 ; chomp $new_name ; # rename imap if ($imap->rename ("user." . $_, "user." . $new_name)) { warn ("can't rename imap box user.".$_.": ".$imap->{Error}."\n") ; syslog ('info',"can't rename imap box user.%s: %s",$_,$imap->{Error}) ; return ; } &exec_jah_admin ("-r",$_,$new_name) ; } else { print "rename $_ impossible\n" ; } } } sub lock_user { syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; foreach (@_) { if (!$opt_j) { &exec_jah_admin ("-l",$_) ; } else { print "lock $_ impossible\n" ; } } } sub unlock_user { syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; foreach (@_) { if (!$opt_j) { &exec_jah_admin ("-u",$_) ; } else { print "unlock $_ impossible\n" ; } } } sub check_password { my $password ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; if ($opt_j) { print "check impossible\n" ; return ; } foreach (@_) { print "$_ Password: " ; Term::ReadKey::ReadMode 'noecho' ; $password = Term::ReadKey::ReadLine 0 ; chomp $password ; Term::ReadKey::ReadMode 'restore' ; print "\n" ; &exec_jah_admin ("-k",$_,$password) ; } } sub change_password { my $new_password,$retype_password ; syslog ('debug',(caller (0))[3]."(".join (",",@_).")") ; if ($opt_j) { print "change password impossible\n" ; return ; } foreach (@_) { print "$_ New password: " ; Term::ReadKey::ReadMode 'noecho' ; $new_password = Term::ReadKey::ReadLine 0 ; chomp $new_password ; Term::ReadKey::ReadMode 'restore' ; print "\n" ; if ($new_password eq "") { warn "Password unchanged\n" ; syslog ('debug','password clear') ; return ; } print "$_ Retype new password: " ; Term::ReadKey::ReadMode 'noecho' ; $retype_password = Term::ReadKey::ReadLine 0 ; chomp $retype_password ; Term::ReadKey::ReadMode 'restore' ; print "\n" ; if ($new_password ne $retype_password) { warn "Mismatch, not changed\n" ; syslog ('debug','mismatch') ; return ; } &exec_jah_admin ("-p",$_,$new_password) ; } } # главная программа # конфигурация getopts ("j") ; if (!defined ($opt_j)) { (POSIX::isatty (STDIN)) || die "Can't use noninteractive tty\n" ; } $PROGRAM_NAME = 'mailadmin' ; $prompt = (getpwuid ($UID))[0]. '@' . $PROGRAM_NAME . '% ' ; $| = 1 ; $imap_hostname = "localhost" ; $imap_admin_username = "mailadmin" ; $imap_admin_password = "" ; $imap_protocol = getprotobyname ('tcp') || 6 ; $imap_port = getservbyname ('imap','tcp') || 143 ; $jah_dbname = "/usr/local/etc/jahpwd.db" ; $jah_admin = "/usr/local/sbin/jahadm" ; $max_command_length = 2 ; $max_history_length = 25 ; setlogsock 'unix' ; openlog ($PROGRAM_NAME,'pid','local0') ; syslog ('info','started by %s',(getpwuid ($UID))[0]) ; $imap = new IMAP::Admin (Server => $imap_hostname, Login => $imap_admin_username, Password => $imap_admin_password, Port => $imap_port) ; $term = new Term::ReadLine ($PROGRAM_NAME) ; # в историю включаем только строки более $max_command_length символов $term->MinLine ($max_command_length+1) ; # в истории храним не более $max_history_length строк $term->StifleHistory ($max_history_length) ; $first_command = 1 ; $last_command = 0 ; while ($opt_j?$command =:defined ($command = $term->readline ($prompt))) { if (length ($command)>$max_command_length && $prev_command eq $command && !$first_command) { # если повторяется последняя команда, оставляем в истории только одну # копию, типа как в deco $term->remove_history ($term->Attribs->{history_length}-1) ; } $first_command = 0 ; # body $command =~ s/^\s+// ; $command =~ s/\s+$// ; ($command,@cmd_args) = split (/\s+/,$command) ; if ($command eq "" or $command =~ /^\?/ or $command =~ /^he?l?p?$/) { &help ; } elsif ($command =~ /^qu?i?t?$/ or $command =~ /^ex?i?t?$/) { $last_command = 1 ; last ; } elsif ($command =~ /^ls$/ or $command =~ /^lis?t?$/) { &list_mailbox (@cmd_args) ; } elsif ($command =~ /^mk$/ or $command =~ /^cre?a?t?e?$/) { &create_mailbox (@cmd_args) ; } elsif ($command =~ /^rm$/ or $command =~ /^del?e?t?e?$/) { &delete_mailbox (@cmd_args) ; } elsif ($command =~ /^mv$/ or $command =~ /^ren?a?m?e?$/) { &rename_mailbox (@cmd_args) ; } elsif ($command =~ /^lk$/ or $command =~ /^loc?k?$/) { &lock_user (@cmd_args) ; } elsif ($command =~ /^ul$/ or $command =~ /^unl?o?c?k?$/) { &unlock_user (@cmd_args) ; } elsif ($command =~ /^che?c?k?$/) { &check_password (@cmd_args) ; } elsif ($command =~ /^pw$/ or $command =~ /^pas?s?w?d?$/) { &change_password (@cmd_args) ; } else { warn "$command " . join (' ',@cmd_args) . ": invalid\n" ; syslog ('info',"invalid command: %s", $command . ' ' . join (' ',@cmd_args)) ; } if (length ($command)>$max_command_length) { $prev_command = $command ; } } syslog ('info','finished by %s',(getpwuid ($UID))[0]) ; closelog ; $imap->close ; if (!$last_command && !$opt_j) { print "\n" ; }
Ходить туда только тем, кому интересно в коде копаться.