Annotation of portolis/portolis.cgi, revision 1.1.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>