#!/usr/bin/perl ####### meta-verify-raq3.pl # # system & database verification and integrity check utility # # Duncan Laurie (duncan@cobalt.com) # (c) 2000 Cobalt Networks, Inc # # ####### OPERATION # # meta-verify-raq3.pl -u|s -a|i|d [-v] [-h] # # -u users # -s virtual sites # # -i repair invalid # -a verify all valid # -d drop table # # -v increase warning level # -h usage help # # ####### USES # # - Verify and repair virtual sites. # - Verify and repair user accounts. # - Maintain intergrity of the RaQ3 system configuration files. # - Ensure coherency between System and Meta/postgreSQL backend. # # ####### DESCRIPTION # # The RaQ3 (all varieties pre Update 2.0) contains a bug w.r.t. handling # single quote characters in vacation messages and usernames that # begin with a decimal digit. The result of this bug is that some or even # all of your users could become "detached" from the Web GUI -- they will # exist on the system but not show up in the Admin interface. # # This script attempts to detect and repair coherency problems that may # result from this bug. It will find invalid (detached) users and # present them as Meta object which can be saved to the postgreSQL backend. # # UPDATE: as of version 2.0 this can now rebuild the virtual site table. # # ####### REQUIREMENTS # # RaQ3 / RaQ3i / RaQ3-ja # # ####### CHANGELOG # # version 2.1 (Apr 18 2000) # - added 'Y' option to say yes to all # # version 2.0 (Mar 01 2000) # - now has support for rebuilding the virtual site list # - command line options have changed # # version 1.2 (Feb 16 2000) # - don't show conflict on self->self aliases # - vacationmsg field is now blank # # version 1.1 (Feb 04 2000) # - fix display of user info that is longer than page width # - fix alias handling # - verifies system is RaQ3 and user is root # # version 1.0 (Feb 03 2000) # - initial release # - fix incorrect reporting of frontpage state # # version 0.9 (Feb 02 2000) # - verify valid user accounts, prompt database update when changes detected # - prompts for and allows database deletion of sites that do not exist in # the system configuration # - fix int() conversion & mismatched parens # # version 0.8 (Feb 01 2000) # - @{ union,intersect,symmetric difference } for database/system user lists # - detect invalid system users correctly # # version 0.7 (Feb 01 2000) # - meta object containing all user fields, completed with information from # current system configuration and state information # # version 0.1 (Jan 31 2000) # - initial creation # # ####### # verify that this is a 3000R my $build_file = "/etc/build"; if (-e $build_file) { if (system("/bin/grep", "-q", "3[01]00R", "$build_file")) { die("\nThis program is only for the RaQ3!\n\n"); } } else { die("\nThis program is only for the RaQ3!\n\n"); } # verify that we are root if ($< != 0) { die("\nThis program must be run as root!\n\n"); } require Cobalt::Meta; require Cobalt::User; require Cobalt::Vacation; require Cobalt::Email; require Cobalt::List; require Cobalt::Fpx; require Cobalt::Ftp; require Cobalt::BandWidth; require Cobalt::Quota; use Getopt::Std; use IO::File; # program info use vars qw($Title $Product $Version $Author $Company); $Product = "meta-verify.pl"; $Title = '"system & database verifier"'; $Author = "Duncan Laurie (duncan\@cobalt.com)"; $Company = "(c) 2000 Cobalt Networks, Inc"; $Version = "2.2"; # program header printf("\n"); printf("%s\n", $Product); printf("%s\n", $Title); printf("version %s\n", $Version); printf("%s\n", $Author); printf("%s\n", $Company); # global variables use vars qw($e %eCOUNT @eALL @eGOOD @eBAD); use vars qw(@eFIELDS @eARRAYS); use vars qw(@all_DB @all_SYS $entryX $entry $entryTYPE); use vars qw($opt_h $opt_u $opt_s $opt_v $opt_a $opt_i $opt_d $opt_l $Verbose); use vars qw($login $message $field $DB_field $SYS_field); # format for output of messages format PRINT_MSG = | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $message ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $message . # format for output of messages format PRINT_ENTRY = @>>>>>>>>>>>>>> | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $login, $message ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $message . # format for output when handling entry errors format PRINT_ENTRY_ERROR = @>>>>>>>>>>>>>> | ERROR ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $login, $message ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $message . # format for output when processing format PRINT_FIELD = @>>>>>>>>>>>>>> | @>>>>>>>>>>>>> = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $login, $field, $message ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $message ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $message . # format for error output when comparing meta+system fields format PRINT_FIELD_ERROR = @>>>>>>>>>>>>>> | ERROR IN @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $login, $field | DATABASE ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $DB_field ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $DB_field ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $DB_field | SYSTEM ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $SYS_field ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $SYS_field ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... $SYS_field . use strict; # command-line arguments, verbose level getopts("suvaihdl"); # usage help if ($opt_h) { printf("\n"); printf(" usage: %s -u|s -a|i|d [-v] [-h]\n", $Product); printf("\n"); printf(" -l reset /home/sites symlinks\n"); printf(" -u verify users\n"); printf(" -s verify virtual sites\n"); printf("\n"); printf(" -i repair invalid\n"); printf(" -a verify valid\n"); printf(" -d drop table\n"); printf("\n"); printf(" -v increase warning level\n"); printf(" -h usage help\n"); printf("\n"); exit 1; } $Verbose = ($opt_v) ? 1 : 0; if ($opt_l) { # reset virtual site symlinks with # entries from /etc/httpd/conf/httpd.conf my $root = "/home/sites"; my $httpd_conf = "/etc/httpd/conf/httpd.conf"; my($vpath,$vhost,$host); unless (-s $httpd_conf) { printf("ERROR: $httpd_conf not found\n"); exit 1; } my $htconf = new IO::File "$httpd_conf"; unless (defined $htconf) { printf("ERROR: unable to open $httpd_conf: $!\n"); exit 1; } print "\n"; while (<$htconf>) { if (m{^} ... m{^}) { if (m{^DocumentRoot $root/([^/]+)/web}) { $entry = $1; $vpath = "$root/$entry"; } elsif (m{^ServerName (.+)}) { $host = $1; $vhost = "$root/$host"; } if (m{^}) { next unless (-d $vpath); unlink $vhost if (-e $vhost); print_entry($host); symlink $vpath, $vhost; $vpath=$vhost=""; } } } print "\n"; undef $htconf; exit 0; } printf("\nchecking system+database coherency...\n"); if ($opt_u) { &setup_users(); } elsif ($opt_s) { &setup_vsite(); } else { printf("error\n - must specify users (-u) or virtual sites (-s)\n\n"); exit 1; } if ($opt_d) { printf("dropping database table...\n"); &Cobalt::Meta::drop($entryTYPE); # { # printf("ERROR - unable to drop database \"$entryTYPE\"\n\n"); # exit 1; # } printf("OK\n\n"); exit 0; } foreach $e (@all_DB, @all_SYS) { $eCOUNT{$e}++; } foreach $e (keys %eCOUNT) { # union - # all in database or system push(@eALL, $e); if ($eCOUNT{$e} == 2) { # intersection - # both in database and in system push(@eGOOD, $e); } else { # symmetric difference - # either not in database or not in system push(@eBAD, $e); } } # output NUMBERS print "\n"; printf(" database | %d\n", scalar(@all_DB)); printf(" system | %d\n", scalar(@all_SYS)); printf(" total | %d\n", scalar(@eALL)); printf(" valid | %d\n", scalar(@eGOOD)); printf(" invalid | %d\n", scalar(@eBAD)); print "\n"; if ($opt_a) { printf("verifying %d VALID %s...\n\n", scalar(@eGOOD), (($opt_s) ? "virtual site(s)" : "user(s)")); &examine_valid(@eGOOD); } elsif ($opt_i) { printf("repairing %d INVALID %s...\n\n", scalar(@eBAD), (($opt_s) ? "virtual site(s)" : "user(s)")); &examine_invalid(@eBAD) if (scalar(@eBAD)); } else { printf("error - must specify valid (-a) or invalid (-i)\n\n"); exit 1; } print "\n" unless ($Verbose); printf("OK\n\n"); exit 0; 1; sub print_msg { $message = "@_"; $~ = 'PRINT_MSG'; write(); } sub print_entry { $message = "@_"; $login = "$entry"; $~ = 'PRINT_ENTRY'; write(); } sub print_entry_error { $message = "(@_)"; $login = "$entry"; $~ = 'PRINT_ENTRY_ERROR'; write(); } sub print_field { ($field,$message) = (@_); $login = "$entry"; $~ = 'PRINT_FIELD'; write(); } sub print_field_error { ($field,$DB_field,$SYS_field) = (@_); $field = "($field)"; $DB_field = "($DB_field)"; $SYS_field = "($SYS_field)"; $login = "$entry"; $~ = 'PRINT_FIELD_ERROR'; write(); } # examine_invalid () # # check the LIST for invalid # correct the problem if possible # # arg: list to check # sub examine_invalid () { my (@eLIST) = (@_); my $yes = 0; foreach $entry (@eLIST) { my $inDB = 0; my $inSYS = 0; printf("\n"); # see if this entry exists in the database if (grep(/\b$entry\b/, @all_DB)) { $inDB = 1; } else { $inDB = 0; &print_entry_error("entry does not exist in database"); } # see if this entry exists in the system &print_msg("retrieving information from system...") if ($Verbose); $entryX = &build_system("$entry"); if ($entryX) { $inSYS = 1; } else { &print_entry_error("does not exist in system"); $inSYS = 0; } # in both system and database # this should never happen if ($inSYS && $inDB) { &print_entry_error("entry is already valid"); $entryX->DESTROY(); next; } # in system but not database if ($inSYS) { my $input; # confirm add while ($input !~ /^[Yyn]/ && !$yes) { printf(" | - save ALL\n"); printf(" | - save entry to database\n"); printf(" | - do NOT save entry to database\n"); printf(" | - view info obtained from system\n"); printf(" | save? [Yynv] "); $input = ; $yes++ if ($input =~ /^Y/); # print info if ($input =~ /^v/) { $Verbose++; $entryX->DESTROY(); $entryX = &build_system("$entry"); $Verbose--; } } # always give the chance to bail next if ($input =~ /^n/); # save unless ($entryX->save()) { &print_entry_error("unable to save"); $entryX->DESTROY(); next; } &print_entry("saved"); $entryX->DESTROY(); next; } # in database but not system if ($inDB) { my $input = ''; my $entryY = Cobalt::Meta->new("type" => "$entryTYPE"); # confirm database entry delete while ($input !~ /^[yn]/) { printf(" | - remove database entry\n"); printf(" | - do NOT remove database entry\n"); printf(" | remove? [yn] "); $input = ; } # always give the chance to bail next if ($input =~ /^n/); # delete entry $entryY->retrieve("$entry"); unless ($entryY->delete()) { &print_entry_error("unable to remove"); $entryY->DESTROY(); next; } $entryY->DESTROY(); &print_entry("removed"); next; } # not in database or system &print_entry_error("entry not in database OR system"); next; } return; } # examine_valid () # # check the LIST for valid and verify # coherency of fields between system and database # # correct the problem if possible # # arg: list to check # sub examine_valid () { my (@eLIST) = (@_); foreach $entry (@eLIST) { # this entry from the database my $entry_DB = (Cobalt::Meta->new("type" => "$entryTYPE")); unless ($entry_DB->retrieve("$entry")) { &print_entry_error("entry non-existant in database"); next; } # get info from the system my $entry_SYS = &build_system("$entry"); unless ($entry_SYS) { &print_entry_error("entry does not exist in system"); next; } # compare fields my $errcount = 0; foreach my $fld (@eFIELDS) { if ($entry_DB->{$fld} ne $entry_SYS->{$fld}) { $errcount++; &print_field_error($fld, $entry_DB->{$fld}, $entry_SYS->{$fld}); } } foreach my $fld (@eARRAYS) { my ($e,@aDB,@aSYS,%count,@diff); # turn flat string into list @aDB = split(' ', $entry_DB->{$fld}); @aSYS = split(' ', $entry_SYS->{$fld}); # compute difference of lists foreach $e (@aDB, @aSYS) { $count{$e}++ } foreach $e (keys %count) { push (@diff, $e) unless ($count{$e} == 2) } # if difference then error if (scalar(@diff)) { $errcount++; &print_field_error($fld, join(', ', @aDB), join(', ', @aSYS)); } } if ($errcount) { my $input; # confirm database update while ($input !~ /^[yn]/) { printf(" | - update database info for entry\n"); printf(" | - do NOT update database\n"); printf(" | update? [yn] "); $input = ; } # always give the chance to bail if ($input =~ /^n/) { print "\n"; next; } # save unless ($entry_SYS->save()) { &print_entry_error("unable to save"); print "\n"; } else { &print_entry("updated"); print "\n"; } } else { &print_entry("ok"); print "\n" if ($Verbose); } $entry_DB->DESTROY(); $entry_SYS->DESTROY(); } return; } sub setup_users () { $entryTYPE = "users"; # some global variables # user fields to compare when verifying all users @eFIELDS = ("name", "fullname", "uid", "vsite", "quota", "vacation", "admin", "shell", "apop", "fpx", "suspend"); # these fields are to be treated as arrays # where order does NOT matter @eARRAYS = ("forward", "aliases"); # the global database views and Meta objects $entryX = Cobalt::Meta->new("type" => "users"); @all_DB = $entryX->getall(); @all_SYS = Cobalt::User::user_list(); # remove admin from both sets @all_SYS = grep !/\bdefault\b/, @all_SYS; @all_SYS = grep !/\badmin\b/, @all_SYS; @all_DB = grep !/\bdefault\b/, @all_DB; @all_DB = grep !/\badmin\b/, @all_DB; if ($Verbose) { print "\n"; foreach $e (@all_DB) { &print_field("db user", $e); } foreach $e (@all_SYS) { &print_field("sys user", $e); } print "\n"; } } sub setup_vsite () { $entryTYPE = "vsite"; # some global variables # user fields to compare when verifying all users @eFIELDS = ("emaildomain", "name", "suspend", "fqdn", "quota", "ftp", "fpx", "ssi", "ssl", "cgi", "ipaddr", "webdomain", "bwlimit", "domain", "hostname"); # these fields are to be treated as arrays # where order does NOT matter @eARRAYS = (); # the global database views and Meta objects $entryX = Cobalt::Meta->new("type" => "vsite"); @all_DB = $entryX->getall(); map { push @all_SYS, @$_[2]; } (Cobalt::Vsite::vsite_list()); # remove from both sets @all_SYS = grep !/\bdefault\b/, @all_SYS; @all_DB = grep !/\bdefault\b/, @all_DB; if ($Verbose) { print "\n"; foreach $e (@all_DB) { &print_field("db vsite", $e); } foreach $e (@all_SYS) { &print_field("sys vsite", $e); } print "\n"; } } sub build_system () { my $ebuild = shift; return unless ($ebuild); if ($entryTYPE eq "users") { return build_user_system($ebuild); } elsif ($entryTYPE eq "vsite") { return build_vsite_system($ebuild); } return; } sub build_vsite_system () { my $site = shift; return unless ($site); my(@tmpARRAY); my($newVSITE) = Cobalt::Meta->new("type" => "vsite"); $newVSITE->put("name" => "$site", # network info "ipaddr" => "", "hostname" => "", "domain" => "", "fqdn" => "", # configuration values "maxusers" => 100, "quota" => 1000, "ftpquota" => 20, "ftpusers" => 10, "gid" => 0, # default options to off "ftp" => "off", "fpx" => "off", "ssi" => "off", "cgi" => "off", "ssl" => "off", "apop" => "off", "shell" => "off", "suspend" => "off", "bwlimit" => "off", "webdomain" => "off", "emaildomain" => "off", # user defaults "userlist_range" => 15, "userlist_sort" => "name", "user_namegen" => 0, "user_quota" => 10, "user_shell" => "off", "user_fpx" => "off", "user_apop" => "off" ); &print_field("group", $newVSITE->get("name")) if ($Verbose); # verify the group existance unless (Cobalt::Group::group_exist("$site")) { &print_entry_error("group does not exist"); return; } # retrieve network info from httpd.conf my($ipaddr,$fqdn) = (Cobalt::Vsite::vsite_get_bygroup("$site"))[0,1]; unless ($ipaddr && $fqdn) { &print_entry_error("does not exist in apache configuration"); return; } $newVSITE->put("ipaddr", "$ipaddr"); &print_field("ipaddr", $newVSITE->get("ipaddr")) if ($Verbose); $newVSITE->put("fqdn", "$fqdn"); &print_field("fqdn", $newVSITE->get("fqdn")) if ($Verbose); # parse fqdn for hostname+domain unless ($fqdn =~ /([-\w]+)\.([-\w\.]+)/) { &print_entry_error("unable to split \"$fqdn\" into hostname+domain"); return; } my($hostname,$domain) = ($1,$2); $newVSITE->put("hostname", "$1"); &print_field("hostname", $newVSITE->get("hostname")) if ($Verbose); $newVSITE->put("domain", "$2"); &print_field("domain", $newVSITE->get("domain")) if ($Verbose); # get the GID $newVSITE->put("gid", (getgrnam("$site"))[2]); &print_field("GID", $newVSITE->get("gid")) if ($Verbose); # see if this has a serveralias for the domain (webdomain) my($found) = 0; if (Cobalt::Util::FILE_lock_r("/etc/httpd/conf/httpd.conf", *HTCONF)) { while () { if (m%^$% ... m%^$%) { $found = 1 if (m%^DocumentRoot /home/sites/\Q$site\E/web$%); if ($found) { last if (m%^$%); if (m%^ServerAlias \Q$domain\E$%) { $newVSITE->put("webdomain", "on"); last; } } } } Cobalt::Util::FILE_unlock(*HTCONF); } else { &print_entry_error("cannot open apache config file") if ($Verbose); } &print_field("web \@domain", $newVSITE->get("webdomain")) if ($Verbose); # get emaildomain setting my(%routes) = Cobalt::Email::mail_virtuser_list_route(); $newVSITE->put("emaildomain", exists($routes{"$domain"}) ? "on" : "off"); &print_field("email \@domain", $newVSITE->get("emaildomain")) if ($Verbose); # get disk quota my($quota) = (Cobalt::Quota::repquota("$site", 1))[1]; if ($quota > 0) { $newVSITE->put("quota", int(($quota * 1024) / 1048576)); } &print_field("disk quota", $newVSITE->get("quota")) if ($Verbose); # get anon ftp settings from proftpd config file my($ftp,$ftpusers,$ftpquota) = Cobalt::Ftp::ftp_get_anonymous("$site"); if ($ftp) { $newVSITE->put("ftp", "on"); $newVSITE->put("ftpusers", $ftpusers); if ($ftpquota > 0) { $newVSITE->put("ftpquota", int(($ftpquota * 1024) / 1048576)); } } &print_field("anonymous FTP", $newVSITE->get("ftp")) if ($Verbose); # get suspend flag $newVSITE->put("suspend", (Cobalt::Vsite::vsite_issuspend("$site")) ? "on" : "off"); &print_field("suspended", $newVSITE->get("suspend")) if ($Verbose); # get frontpage settings $newVSITE->put("fpx", (Cobalt::Fpx::fpx_get_web("$site")) ? "on" : "off"); &print_field("frontpage", $newVSITE->get("fpx")) if ($Verbose); # get cgi settings $newVSITE->put("cgi", (Cobalt::Vsite::vsite_get_cgis("$site")) ? "on" : "off"); &print_field("CGI scripts", $newVSITE->get("cgi")) if ($Verbose); # get ssi settings $newVSITE->put("ssi", (Cobalt::Vsite::vsite_get_ssi("$site")) ? "on" : "off"); &print_field("SSI scripts", $newVSITE->get("ssi")) if ($Verbose); # get ssl settings $newVSITE->put("ssl", (-f "/etc/httpd/ssl/$site") ? "on" : "off"); &print_field("SSL server", $newVSITE->get("ssl")) if ($Verbose); # attempt to get bandwidth limit $newVSITE->put("bwlimit", (Cobalt::BandWidth::bw_getip("$ipaddr") > 0) ? "on" : "off"); &print_field("bandwidth", $newVSITE->get("bwlimit")) if ($Verbose); printf("\n") if ($Verbose); return $newVSITE; } # build_user_system () # # tries to build a Meta object of type "users" # from information gathered by the system # # arg: login name # ret: Meta object (type => users) # sub build_user_system () { my $user = shift; return unless ($user); my (@tmpARRAY); my $newUSER = Cobalt::Meta->new("type" => "users"); # get basic user info my ($name,$uid,$fullname,$dir,$sh) = (getpwnam("$user"))[0,2,6,7,8]; unless ($name) { &print_entry_error("does not exist in password file"); return; } # determine virtual site from home directory path my $vsite; if ($dir =~ m|^/home/sites/home/users/|) { $vsite = "home"; } elsif ($dir =~ m|^/home/sites/(site[0-9]+)/users/|) { $vsite = "$1"; } else { &print_entry_error("invalid home directory"); return; } printf("\n") if ($Verbose); # user name $newUSER->put("name", "$name"); &print_field("user name", $name) if ($Verbose); # full name $newUSER->put("fullname", "$fullname"); $newUSER->put("altname", ""); &print_field("full name", $fullname) if ($Verbose); # UID $newUSER->put("uid", "$uid"); &print_field("UID", $uid) if ($Verbose); # virtual site membership $newUSER->put("vsite", "$vsite"); &print_field("virtual site", $vsite) if ($Verbose); # disk quota my($quota) = (Cobalt::Quota::repquota("$user"))[1]; $newUSER->put("quota", (($quota > 0) ? int(($quota * 1024) / 1048576) : 0)); &print_field("disk quota", $newUSER->get("quota")) if ($Verbose); # email aliases my $aliases = ""; @tmpARRAY = (Cobalt::Email::mail_virtuser_get_byuser("$user")); if (scalar(@tmpARRAY)) { # remove domains my @oARRAY; foreach (@tmpARRAY) { if (/^([^@]+)\@.*/) { push(@oARRAY, $1) unless($1 eq $user); } else { push(@oARRAY, $_); } } $aliases = join(" ", @oARRAY); } $newUSER->put("aliases", "$aliases"); &print_field("email aliases", $aliases) if ($Verbose); # email forwarding @tmpARRAY = (Cobalt::List::alias_get_vacationless("$user")); $newUSER->put("forward", ((scalar(@tmpARRAY) > 0) ? join(" ", @tmpARRAY) : "off")); &print_field("email forward", $newUSER->get("forward")) if ($Verbose); # virtual site administrator @tmpARRAY = (Cobalt::User::user_list_groups("$user")); $newUSER->put("admin", ((scalar(grep(/\b$vsite\b/, @tmpARRAY))) ? "on" : "off")); &print_field("site admin", $newUSER->get("admin")) if ($Verbose); # suspended user $newUSER->put("suspend", ((Cobalt::User::user_issuspend("$user")) ? "on" : "off")); &print_field("suspended", $newUSER->get("suspend")) if ($Verbose); # telnet/shell access $newUSER->put("shell", (($sh eq "/bin/bash") ? "on" : "off")); &print_field("telnet/shell", $newUSER->get("shell")) if ($Verbose); # authenticated pop3 (APOP) $newUSER->put("apop", ((Cobalt::Email::mail_apop_isuser("$user")) ? "on" : "off")); &print_field("secure POP3", $newUSER->get("apop")) if ($Verbose); # frontpage extensions @tmpARRAY = (Cobalt::Vsite::vsite_get_fpx("$vsite")); $newUSER->put("fpx", ((scalar(grep(/\b$user\b/, @tmpARRAY))) ? "on" : "off")); &print_field("frontpage", $newUSER->get("fpx")) if ($Verbose); # email vacation responder $newUSER->put("vacation", ((Cobalt::Vacation::vacation_get_on("$user")) ? "on" : "off")); &print_field("vacation", $newUSER->get("vacation")) if ($Verbose); $newUSER->put("vacationmsg", ""); printf("\n") if ($Verbose); return $newUSER; }