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 © 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>