Annotation of portolis/portolis.cgi, revision 1.1

1.1     ! snw         1: #!/usr/pkg/bin/perl
        !             2: 
        !             3: #
        !             4: # Portolis Mail Management Portal
        !             5: #  Copyright (C) 2025 Coherent Logic Development LLC
        !             6: #
        !             7: # $Id$
        !             8: #  Author: Serena Willis <snw@coherent-logic.com>
        !             9: #
        !            10: # Licensed AGPL-3.0
        !            11: #
        !            12: # $Log$
        !            13: #
        !            14: 
        !            15: use CGI qw(:standard);
        !            16: use CGI::Session;
        !            17: 
        !            18: $portolis_version = '0.0.4';
        !            19: $session = CGI::Session->new();
        !            20: 
        !            21: sub init
        !            22: {
        !            23:     $cookie = cookie(CGISESSID => $session->id );
        !            24:     print header(-cookie=>$cookie);
        !            25: }
        !            26: 
        !            27: sub find_alias {
        !            28:     my ($target, $alias) = @_;
        !            29: 
        !            30:     open(FH, '<', '/etc/postfix/virtual_aliases');
        !            31: 
        !            32:     while(<FH>) {
        !            33:        my @entry = split(' ', $_);
        !            34:        my $falias = $entry[0];
        !            35:        my $ftarget = $entry[1];
        !            36: 
        !            37:        if(($ftarget eq $target) && ($falias eq $alias)) {
        !            38:            close FH;
        !            39:            return 1;
        !            40:        }
        !            41:     }
        !            42: 
        !            43:     close FH;
        !            44:     return 0;
        !            45: }
        !            46: 
        !            47: sub add_alias {
        !            48:     my ($target, $alias) = @_;
        !            49: 
        !            50: }
        !            51: 
        !            52: sub vmail_auth {
        !            53:     my ($auser, $apass) = @_;
        !            54: 
        !            55:     my $line = "";
        !            56:     my @pwent = ();
        !            57:     
        !            58:     open(FH, "<", "/usr/pkg/etc/dovecot/users");
        !            59: 
        !            60:     while(<FH>){       
        !            61:        $line = $_;
        !            62:        @pwent = split(':', $line);
        !            63:        if($pwent[0] eq $auser) {
        !            64: 
        !            65:            my $result = `/usr/pkg/bin/doveadm pw -t \'$pwent[1]\' -p \'$apass\'`;
        !            66:            my @res = split(' ', $result);
        !            67:            
        !            68:            if($res[1] eq "(verified)") {
        !            69:                close FH;
        !            70:                return 1;
        !            71:            }
        !            72:        }
        !            73:     }
        !            74: 
        !            75:     close FH;
        !            76:     return 0;        
        !            77: }
        !            78: 
        !            79: sub render_header {
        !            80:     my ($title) = @_;
        !            81: 
        !            82:     my $navbar = '';
        !            83:     my $html = <<"END_HDR";
        !            84: <HTML>
        !            85: <HEAD>
        !            86: <TITLE>$title</TITLE>
        !            87: </HEAD>
        !            88: <BODY BGCOLOR=PaleGoldenrod>
        !            89: END_HDR
        !            90: 
        !            91:     print $html;
        !            92:     
        !            93:     if($session->param("~logged-in")) {
        !            94:        my $email = $session->param("~email");
        !            95:        $navbar = <<"END_NAVL";
        !            96: <A HREF=/cgi-bin/portolis.cgi?exec=home>$email</A> | <A HREF=https://webmail.coherent-logic.com>WebMail</A> | <A HREF=/cgi-bin/portolis.cgi?exec=logout>Log out</A>
        !            97: <HR>
        !            98: END_NAVL
        !            99:     }
        !           100:     else {
        !           101:        $navbar = <<"END_NAVO";
        !           102: <A HREF=https://webmail.coherent-logic.com>WebMail</A> | <A HREF=/cgi-bin/portolis.cgi?exec=login>Log In</A>
        !           103: <HR>
        !           104: END_NAVO
        !           105:     }
        !           106: 
        !           107:     print $navbar;
        !           108:     
        !           109: }
        !           110: 
        !           111: sub render_footer {
        !           112: 
        !           113:     my $html = <<'END_FTR';
        !           114: <HR>
        !           115: <EM>$Id$<BR>
        !           116: Copyright &copy; 2025 Coherent Logic Development LLC</EM>
        !           117: </BODY>
        !           118: </HTML>
        !           119: END_FTR
        !           120: 
        !           121:     print $html;
        !           122: }
        !           123: 
        !           124: sub list_aliases {
        !           125:     my $email = $session->param("~email");
        !           126:     open(FH, '<', '/etc/postfix/virtual_aliases');
        !           127: 
        !           128:     print "<TABLE CELLPADDING=3 CELLSPACING=0 BORDER=1>";
        !           129:     print "<TR><TH>Alias</TH><TH>Actions</TH></TR>";
        !           130:     while(<FH>) {
        !           131:        my $ln = $_;
        !           132:        my @line = split(' ', $ln);
        !           133:        
        !           134:        if($line[1] eq $email) {
        !           135:            print "<TR><TD>$line[0]</TD><TD><A HREF=/cgi-bin/portolis.cgi?exec=delalias&id=$line[0]>Delete</A></TD></TR>";
        !           136:        }
        !           137:     }
        !           138:     print "</TABLE>";
        !           139:     print "<A HREF=/cgi-bin/portolis.cgi?exec=newalias>New Alias</A>";
        !           140:     close FH;
        !           141: }
        !           142: 
        !           143: sub exec_home {
        !           144:     render_header "Home";
        !           145:     my $email = $session->param("~email");
        !           146:     my $html = <<"END_HOME";
        !           147:     <CENTER>
        !           148:     <H1>Account Overview</H1>
        !           149:     <P>Your e-mail address is <B>$email</B></P>
        !           150: END_HOME
        !           151: 
        !           152:     print $html;
        !           153: 
        !           154:     list_aliases();
        !           155: 
        !           156:     print "</CENTER>";
        !           157: }
        !           158: 
        !           159: sub exec_newalias {
        !           160:     my $html = '';
        !           161: 
        !           162:     if($session->param("~logged-in") == 0) {
        !           163:        render_header "Access Denied";
        !           164:        $html = <<"END_BADNAF";
        !           165:        <H1>Access Denied</H1>
        !           166:        <P>You are not logged in.</P>
        !           167: END_BADNAF
        !           168: 
        !           169:        print $html;
        !           170:        return;
        !           171:     }    
        !           172: 
        !           173:     my $email = $session->param("~email");
        !           174:     render_header "New Alias";
        !           175:     
        !           176:     if(request_method() eq 'GET') {
        !           177:        $html = <<"END_NAF";
        !           178:        <CENTER>
        !           179:        <H1>Create New Alias</H1>
        !           180:        <FORM METHOD=POST ACTION=/cgi-bin/portolis.cgi?exec=newalias>
        !           181:        <TABLE CELLPADDING=3 CELLSPACING=0 BORDER=1>
        !           182:        <TR>
        !           183:        <TD><B>Alias:</B></TD>
        !           184:        <TD><INPUT TYPE=TEXT NAME=alias></TD>
        !           185:        </TR>
        !           186:        <TR>
        !           187:        <TD><B>Target:</B></TD>
        !           188:        <TD>$email</TD>
        !           189:        </TR>
        !           190:        <TR>
        !           191:        <TD COLSPAN=2 ALIGN=RIGHT>
        !           192:        <INPUT TYPE=SUBMIT NAME=SUBMIT VALUE=Submit>
        !           193:        </TD>
        !           194:        </TR>
        !           195:        </TABLE>
        !           196:        </FORM>
        !           197:        </CENTER>
        !           198: END_NAF
        !           199:     }
        !           200:     else {
        !           201:        my $proposed = param("alias");
        !           202:        my $result = find_alias($email, $proposed);
        !           203: 
        !           204:        if($result == 0) {
        !           205:            open(FH, '>>', '/etc/postfix/virtual_aliases');
        !           206:            flock(FH, 2);
        !           207:            print FH "$proposed\t$email\n";
        !           208:            flock(FH, 8);
        !           209:            close(FH);
        !           210:            chdir '/etc/postfix';
        !           211:            system '/usr/sbin/postmap virtual_aliases';
        !           212:            $html = <<"END_AAOK";
        !           213:            <CENTER>
        !           214:            <H1>Alias Added</H1>
        !           215:            <A HREF=/cgi-bin/portolis.cgi?exec=home>Home</A>
        !           216:            </CENTER>
        !           217: END_AAOK
        !           218:        }
        !           219:        else {
        !           220:            $html = <<"END_AADUP";
        !           221:            <CENTER>
        !           222:            <H1>Duplicate Alias</H1>
        !           223:            <P>The alias <B>$proposed</B> already exists</P>
        !           224:            <A HREF=/cgi-bin/portolis.cgi?exec=newalias>Try Again</a>
        !           225:            </CENTER>
        !           226: END_AADUP
        !           227:        }
        !           228:     }
        !           229: 
        !           230:     print $html;
        !           231: 
        !           232: }
        !           233: 
        !           234: sub exec_delalias {
        !           235:     my $alias = url_param('id');
        !           236:     my $html = '';
        !           237:     
        !           238:     if($session->param("~logged-in") == 0) {
        !           239:        render_header "Access Denied";
        !           240:        $html = <<"END_BADDAF";
        !           241:        <H1>Access Denied</H1>
        !           242:        <P>You are not logged in.</P>
        !           243: END_BADDAF
        !           244: 
        !           245:        print $html;
        !           246:        return;
        !           247:     }
        !           248:     
        !           249:     my $email = $session->param("~email");
        !           250:     render_header "Delete Alias";
        !           251:     
        !           252:     if(request_method() eq 'GET') {
        !           253:        if(find_alias($email, $alias) == 1) {
        !           254:            my @lines = ();
        !           255: 
        !           256:            open(FH, '<', '/etc/postfix/virtual_aliases');
        !           257:            flock(FH, 2);
        !           258:            while(<FH>) {
        !           259:                my $line = $_;
        !           260:                my @tmp = split(' ', $line);
        !           261:                if($tmp[0] ne $alias) {
        !           262:                    push @lines, $line;
        !           263:                }
        !           264:                if(($tmp[0] eq $alias) && ($tmp[1] ne $email)) {
        !           265:                    push @lines, $line;
        !           266:                }
        !           267:            }
        !           268:            flock(FH, 8);
        !           269:            close(FH);
        !           270:            open(FH, '>', '/etc/postfix/virtual_aliases');
        !           271:            flock(FH, 2);
        !           272:            seek(FH, 0, 0);
        !           273:            truncate(FH, 0);
        !           274:            print FH @lines;
        !           275:            flock(FH, 8);
        !           276:            close FH;
        !           277:            chdir '/etc/postfix';
        !           278:            system '/usr/sbin/postmap virtual_aliases';
        !           279:            $html = <<"END_DAGOOD";
        !           280:            <CENTER>
        !           281:            <H1>Alias Deleted</H1>
        !           282:            <P><A HREF=/cgi-bin/portolis.cgi?exec=home>Home</A>
        !           283:            </CENTER>
        !           284: END_DAGOOD
        !           285:        }
        !           286:        else {
        !           287:            $html = <<"END_DANOF";
        !           288:            <CENTER>
        !           289:            <H1>Invalid Alias</H1>
        !           290:            <P><A HREF=/cgi-bin/portolis.cgi?exec=home>Home</A>
        !           291:            </CENTER>
        !           292: END_DANOF
        !           293:        }
        !           294:     }
        !           295:     
        !           296:     print $html;
        !           297:     
        !           298: }
        !           299: 
        !           300: sub exec_login {
        !           301: 
        !           302:     render_header "Login";
        !           303:     
        !           304:     my $html = '';
        !           305:     
        !           306:     if(request_method() eq 'GET') {
        !           307:        $html = <<"END_LOGIN";
        !           308: <CENTER>
        !           309: <H1>Log In</H1>
        !           310: <FORM METHOD=POST ACTION=/cgi-bin/portolis.cgi?exec=login>
        !           311: <TABLE CELLPADDING=3 CELLSPACING=0 BORDER=1>
        !           312: <tr>
        !           313:   <td><b>E-Mail Address:</b></td>
        !           314:   <td><input type="text" name="email"></td>
        !           315: </tr>
        !           316: <tr>
        !           317:   <td><b>Password:</b></td>
        !           318:   <td><input type="password" name="password"></td>
        !           319: </tr>
        !           320: <tr>
        !           321:   <td colspan=2 align=right><input type=submit name=submit value=Submit></td>
        !           322: </tr>
        !           323: </TABLE>
        !           324: </FORM>
        !           325: </CENTER>
        !           326: END_LOGIN
        !           327:     }
        !           328:     elsif(request_method() eq 'POST') {
        !           329:        my $email = param("email");
        !           330:        my $password = param("password");
        !           331: 
        !           332:        if(vmail_auth($email, $password) == 1) {
        !           333:            $session->param("~logged-in", 1);
        !           334:            $session->param("~email", $email);
        !           335:            $html = <<'END_LOGINDONE';
        !           336:                <script>location.replace('/cgi-bin/portolis.cgi?exec=home');</script>
        !           337: 
        !           338: END_LOGINDONE
        !           339:        }
        !           340:        else {
        !           341:            $html = <<'END_ACD';
        !           342: <H1>Access Denied</H1>
        !           343:            <P>Invalid e-mail address or password</P>
        !           344: END_ACD
        !           345:        }
        !           346:     }
        !           347: 
        !           348:     print $html;
        !           349:        
        !           350:        
        !           351: }
        !           352: 
        !           353: sub exec_logout {
        !           354:     $session->clear(['~logged-in', 'email']);
        !           355:     my $html = <<'END_LO';
        !           356:     <script>location.replace('/cgi-bin/portolis.cgi?exec=login');</script>
        !           357: END_LO
        !           358:     print $html;
        !           359: }
        !           360: 
        !           361: sub exec_unknown {
        !           362: 
        !           363:     render_header "Error";
        !           364:     
        !           365:     my $html = <<'END_UNK';
        !           366: <CENTER>
        !           367:    <H1>Invalid Request</H1>
        !           368: <P>The action you're attempting is invalid or has not yet been implemented. Please try something else.</P>
        !           369: </CENTER>
        !           370: END_UNK
        !           371: 
        !           372:     print $html;
        !           373:     
        !           374: }
        !           375: 
        !           376: sub main {    
        !           377:     init;
        !           378: 
        !           379:     my $exec = url_param('exec');
        !           380:     
        !           381:     if($exec ne '') {  
        !           382:        if($exec eq 'login') {
        !           383:            $funcref = \&exec_login;
        !           384:        }
        !           385:        elsif($exec eq 'logout') {
        !           386:            $funcref = \&exec_logout;
        !           387:        }
        !           388:        elsif($exec eq 'home') {
        !           389:            $funcref = \&exec_home;
        !           390:        }
        !           391:        elsif($exec eq 'newalias') {
        !           392:            $funcref = \&exec_newalias;
        !           393:        }
        !           394:        elsif($exec eq 'delalias') {
        !           395:            $funcref = \&exec_delalias;
        !           396:        }
        !           397:        else {
        !           398:            $funcref = \&exec_unknown;
        !           399:        }
        !           400:     }
        !           401:     else {
        !           402:        $funcref = \&exec_login;
        !           403:     }
        !           404: 
        !           405:     &$funcref;
        !           406:     
        !           407:     render_footer;
        !           408: }
        !           409: 
        !           410: main();
        !           411: 
        !           412: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>