Blame


1 84c190b6 2021-12-17 jrmu #!/usr/bin/perl
2 84c190b6 2021-12-17 jrmu
3 84c190b6 2021-12-17 jrmu package Shell;
4 84c190b6 2021-12-17 jrmu
5 84c190b6 2021-12-17 jrmu use strict;
6 84c190b6 2021-12-17 jrmu use warnings;
7 84c190b6 2021-12-17 jrmu use OpenBSD::Pledge;
8 84c190b6 2021-12-17 jrmu use OpenBSD::Unveil;
9 84c190b6 2021-12-17 jrmu use MIME::Base64;
10 84c190b6 2021-12-17 jrmu use Data::Dumper;
11 84c190b6 2021-12-17 jrmu use Digest::SHA qw(sha256_hex);
12 84c190b6 2021-12-17 jrmu use lib './';
13 84c190b6 2021-12-17 jrmu require "SQLite.pm";
14 84c190b6 2021-12-17 jrmu require "Hash.pm";
15 84c190b6 2021-12-17 jrmu
16 84c190b6 2021-12-17 jrmu my %conf = %main::conf;
17 84c190b6 2021-12-17 jrmu my $chans = $conf{chans};
18 84c190b6 2021-12-17 jrmu my $teamchans = $conf{teamchans};
19 84c190b6 2021-12-17 jrmu my @teamchans = split /[,\s]+/m, $teamchans;
20 84c190b6 2021-12-17 jrmu my $staff = $conf{staff};
21 84c190b6 2021-12-17 jrmu my $captchaURL = "https://example.com/captcha.php?vhost=";
22 84c190b6 2021-12-17 jrmu my $hostname = $conf{hostname};
23 84c190b6 2021-12-17 jrmu my $terms = $conf{terms};
24 84c190b6 2021-12-17 jrmu my $expires = $conf{expires};
25 84c190b6 2021-12-17 jrmu my $mailfrom = $conf{mailfrom};
26 84c190b6 2021-12-17 jrmu my $mailname = $conf{mailname};
27 84c190b6 2021-12-17 jrmu my $passpath = "/etc/passwd";
28 84c190b6 2021-12-17 jrmu my $httpdconfpath = "/etc/httpd.conf";
29 84c190b6 2021-12-17 jrmu my $acmeconfpath = "/etc/acme-client.conf";
30 84c190b6 2021-12-17 jrmu my $pfconfpath = "/etc/pf.conf";
31 84c190b6 2021-12-17 jrmu my $relaydconfpath = "/etc/relayd.conf";
32 84c190b6 2021-12-17 jrmu my $startPort;
33 84c190b6 2021-12-17 jrmu my $endPort;
34 84c190b6 2021-12-17 jrmu main::cbind("pub", "-", "shell", \&mshell);
35 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "shell", \&mshell);
36 84c190b6 2021-12-17 jrmu
37 84c190b6 2021-12-17 jrmu sub init {
38 84c190b6 2021-12-17 jrmu #dependencies for figlet
39 84c190b6 2021-12-17 jrmu unveil("/usr/local/bin/figlet", "rx") or die "Unable to unveil $!";
40 84c190b6 2021-12-17 jrmu unveil("/usr/lib/libc.so.95.1", "r") or die "Unable to unveil $!";
41 84c190b6 2021-12-17 jrmu unveil("/usr/libexec/ld.so", "r") or die "Unable to unveil $!";
42 84c190b6 2021-12-17 jrmu #dependencies for shell account
43 84c190b6 2021-12-17 jrmu unveil($passpath, "r") or die "Unable to unveil $!";
44 84c190b6 2021-12-17 jrmu unveil($httpdconfpath, "rwxc") or die "Unable to unveil $!";
45 84c190b6 2021-12-17 jrmu unveil($acmeconfpath, "rwxc") or die "Unable to unveil $!";
46 84c190b6 2021-12-17 jrmu unveil($pfconfpath, "rwxc") or die "Unable to unveil $!";
47 84c190b6 2021-12-17 jrmu unveil($relaydconfpath, "rwxc") or die "Unable to unveil $!";
48 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/chown", "rx") or die "Unable to unveil $!";
49 84c190b6 2021-12-17 jrmu unveil("/bin/chmod", "rx") or die "Unable to unveil $!";
50 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/groupadd", "rx") or die "Unable to unveil $!";
51 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/useradd", "rx") or die "Unable to unveil $!";
52 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/groupdel", "rx") or die "Unable to unveil $!";
53 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/userdel", "rx") or die "Unable to unveil $!";
54 84c190b6 2021-12-17 jrmu unveil("/bin/mkdir", "rx") or die "Unable to unveil $!";
55 84c190b6 2021-12-17 jrmu unveil("/bin/ln", "rx") or die "Unable to unveil $!";
56 84c190b6 2021-12-17 jrmu unveil("/usr/sbin/acme-client", "rx") or die "Unable to unveil $!";
57 84c190b6 2021-12-17 jrmu unveil("/bin/rm", "rx") or die "Unable to unveil $!";
58 84c190b6 2021-12-17 jrmu unveil("/bin/mv", "rx") or die "Unable to unveil $!";
59 84c190b6 2021-12-17 jrmu unveil("/home/", "rwxc") or die "Unable to unveil $!";
60 84c190b6 2021-12-17 jrmu }
61 84c190b6 2021-12-17 jrmu
62 84c190b6 2021-12-17 jrmu # !shell <username> <email>
63 84c190b6 2021-12-17 jrmu # !shell captcha <captcha>
64 84c190b6 2021-12-17 jrmu sub mshell {
65 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, @args) = @_;
66 84c190b6 2021-12-17 jrmu my ($chan, $text);
67 84c190b6 2021-12-17 jrmu if (@args == 2) {
68 84c190b6 2021-12-17 jrmu ($chan, $text) = ($args[0], $args[1]);
69 84c190b6 2021-12-17 jrmu } else { $text = $args[0]; }
70 84c190b6 2021-12-17 jrmu my $hostmask = "$nick!$host";
71 84c190b6 2021-12-17 jrmu if (defined($chan) && $chans =~ /$chan/) {
72 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$nick: Please check private message");
73 84c190b6 2021-12-17 jrmu }
74 84c190b6 2021-12-17 jrmu if ($text =~ /^$/) {
75 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Type !help for new instructions");
76 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
77 84c190b6 2021-12-17 jrmu main::putservlocalnet($bot, "PRIVMSG $chan :Help shell *$nick* on ".$bot->{name});
78 84c190b6 2021-12-17 jrmu }
79 84c190b6 2021-12-17 jrmu return;
80 84c190b6 2021-12-17 jrmu } elsif (main::isstaff($bot, $nick) && $text =~ /^delete\s+([[:ascii:]]+)/) {
81 84c190b6 2021-12-17 jrmu my $username = $1;
82 84c190b6 2021-12-17 jrmu if (SQLite::deleterows("shell", "username", $username)) {
83 84c190b6 2021-12-17 jrmu # TODO delete shell
84 84c190b6 2021-12-17 jrmu deleteshell($username);
85 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
86 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$username deleted");
87 84c190b6 2021-12-17 jrmu }
88 84c190b6 2021-12-17 jrmu }
89 84c190b6 2021-12-17 jrmu return;
90 84c190b6 2021-12-17 jrmu }
91 84c190b6 2021-12-17 jrmu ### TODO: Check duplicate emails ###
92 84c190b6 2021-12-17 jrmu my @rows = SQLite::selectrows("irc", "nick", $nick);
93 84c190b6 2021-12-17 jrmu foreach my $row (@rows) {
94 84c190b6 2021-12-17 jrmu my $password = SQLite::get("shell", "ircid", $row->{id}, "password");
95 84c190b6 2021-12-17 jrmu if (defined($password)) {
96 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help.");
97 84c190b6 2021-12-17 jrmu return;
98 84c190b6 2021-12-17 jrmu }
99 84c190b6 2021-12-17 jrmu }
100 84c190b6 2021-12-17 jrmu if ($text =~ /^lastseen\s+([[:alnum:]]+)/) {
101 84c190b6 2021-12-17 jrmu }
102 84c190b6 2021-12-17 jrmu if ($text =~ /^captcha\s+([[:alnum:]]+)/) {
103 84c190b6 2021-12-17 jrmu my $text = $1;
104 84c190b6 2021-12-17 jrmu my $ircid = SQLite::id("irc", "nick", $nick, $expires);
105 84c190b6 2021-12-17 jrmu if (!defined($ircid)) { die "undefined ircid"; }
106 84c190b6 2021-12-17 jrmu my $captcha = SQLite::get("shell", "ircid", $ircid, "captcha");
107 84c190b6 2021-12-17 jrmu if ($text ne $captcha) {
108 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Wrong captcha. To get a new captcha, type !shell <username> <email>");
109 84c190b6 2021-12-17 jrmu return;
110 84c190b6 2021-12-17 jrmu }
111 84c190b6 2021-12-17 jrmu my $pass = Hash::newpass();
112 84c190b6 2021-12-17 jrmu chomp(my $encrypted = `encrypt $pass`);
113 84c190b6 2021-12-17 jrmu my $username = SQLite::get("shell", "ircid", $ircid, "username");
114 84c190b6 2021-12-17 jrmu my $email = SQLite::get("shell", "ircid", $ircid, "email");
115 84c190b6 2021-12-17 jrmu my $version = SQLite::get("shell", "ircid", $ircid, "version");
116 84c190b6 2021-12-17 jrmu my $bindhost = "$username.$hostname";
117 84c190b6 2021-12-17 jrmu SQLite::set("shell", "ircid", $ircid, "password", $encrypted);
118 84c190b6 2021-12-17 jrmu if (DNS::nextdns($username)) {
119 84c190b6 2021-12-17 jrmu sleep(2);
120 84c190b6 2021-12-17 jrmu createshell($username, $pass, $bindhost);
121 84c190b6 2021-12-17 jrmu mailshell($username, $email, $pass, "shell", $version);
122 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Check your email!");
123 84c190b6 2021-12-17 jrmu
124 84c190b6 2021-12-17 jrmu #www($newnick, $reply, $password, "bouncer");
125 84c190b6 2021-12-17 jrmu } else {
126 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
127 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :Assigning bindhost $bindhost failed");
128 84c190b6 2021-12-17 jrmu }
129 84c190b6 2021-12-17 jrmu }
130 84c190b6 2021-12-17 jrmu return;
131 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^([[:alnum:]]+)\s+([[:ascii:]]+)/) {
132 84c190b6 2021-12-17 jrmu my ($username, $email) = ($1, $2);
133 84c190b6 2021-12-17 jrmu my @users = col($passpath, 1, ":");
134 84c190b6 2021-12-17 jrmu my @matches = grep(/^$username$/i, @users);
135 84c190b6 2021-12-17 jrmu if (scalar(@matches) > 0) {
136 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Sorry, username taken. Please choose another username, or contact staff for help.");
137 84c190b6 2021-12-17 jrmu return;
138 84c190b6 2021-12-17 jrmu }
139 84c190b6 2021-12-17 jrmu # my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4;
140 84c190b6 2021-12-17 jrmu my $captcha = int(rand(999));
141 84c190b6 2021-12-17 jrmu my $ircid = int(rand(2147483647));
142 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "localtime", time());
143 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "date", main::date());
144 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "hostmask", $hostmask);
145 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "nick", $nick);
146 84c190b6 2021-12-17 jrmu SQLite::set("shell", "ircid", $ircid, "username", $username);
147 84c190b6 2021-12-17 jrmu SQLite::set("shell", "ircid", $ircid, "email", $email);
148 84c190b6 2021-12-17 jrmu SQLite::set("shell", "ircid", $ircid, "captcha", $captcha);
149 84c190b6 2021-12-17 jrmu main::whois($bot->{sock}, $nick);
150 84c190b6 2021-12-17 jrmu main::ctcp($bot->{sock}, $nick);
151 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`);
152 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :$captchaURL".encode_base64($captcha));
153 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Type !shell captcha <text>");
154 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
155 84c190b6 2021-12-17 jrmu main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s captcha on $bot->{name} is $captcha");
156 84c190b6 2021-12-17 jrmu }
157 84c190b6 2021-12-17 jrmu } else {
158 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !shell <username> <email> to try again.");
159 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
160 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
161 84c190b6 2021-12-17 jrmu }
162 84c190b6 2021-12-17 jrmu }
163 84c190b6 2021-12-17 jrmu }
164 84c190b6 2021-12-17 jrmu sub mailshell {
165 84c190b6 2021-12-17 jrmu my( $username, $email, $password, $service, $version )=@_;
166 84c190b6 2021-12-17 jrmu my $passhash = sha256_hex("$username");
167 84c190b6 2021-12-17 jrmu my $versionhash = encode_base64($version);
168 84c190b6 2021-12-17 jrmu my $body = <<"EOF";
169 84c190b6 2021-12-17 jrmu You created a shell account!
170 84c190b6 2021-12-17 jrmu
171 84c190b6 2021-12-17 jrmu Username: $username
172 84c190b6 2021-12-17 jrmu Password: $password
173 84c190b6 2021-12-17 jrmu Server: $hostname
174 84c190b6 2021-12-17 jrmu SSH Port: 22
175 84c190b6 2021-12-17 jrmu Your Ports: $startPort to $endPort
176 84c190b6 2021-12-17 jrmu
177 84c190b6 2021-12-17 jrmu To customize your vhost, connect to ask in #ircnow
178 84c190b6 2021-12-17 jrmu
179 84c190b6 2021-12-17 jrmu *IMPORTANT*: Verify your email address:
180 84c190b6 2021-12-17 jrmu
181 84c190b6 2021-12-17 jrmu https://www.$hostname/register.php?id=$passhash&version=$versionhash
182 84c190b6 2021-12-17 jrmu
183 84c190b6 2021-12-17 jrmu You *MUST* click on the link within 24 hours or your account will be deleted.
184 84c190b6 2021-12-17 jrmu
185 84c190b6 2021-12-17 jrmu IRCNow
186 84c190b6 2021-12-17 jrmu EOF
187 84c190b6 2021-12-17 jrmu Mail::mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body);
188 84c190b6 2021-12-17 jrmu }
189 84c190b6 2021-12-17 jrmu
190 84c190b6 2021-12-17 jrmu
191 84c190b6 2021-12-17 jrmu #sub mregex {
192 84c190b6 2021-12-17 jrmu # my ($bot, $nick, $host, $hand, $text) = @_;
193 84c190b6 2021-12-17 jrmu # if ($staff !~ /$nick/) { return; }
194 84c190b6 2021-12-17 jrmu # if ($text =~ /^ips?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
195 84c190b6 2021-12-17 jrmu # my $ips = $1; # space-separated list of IPs
196 84c190b6 2021-12-17 jrmu # main::putserv($bot, "PRIVMSG $nick :".regexlist($ips));
197 84c190b6 2021-12-17 jrmu # } elsif ($text =~ /^users?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
198 84c190b6 2021-12-17 jrmu # my $users = $1; # space-separated list of usernames
199 84c190b6 2021-12-17 jrmu # main::putserv($bot, "PRIVMSG $nick :".regexlist($users));
200 84c190b6 2021-12-17 jrmu # } elsif ($text =~ /^[-_()|0-9A-Za-z:,\.?*\s]{3,}$/) {
201 84c190b6 2021-12-17 jrmu # my @lines = regex($text);
202 84c190b6 2021-12-17 jrmu # foreach my $l (@lines) { print "$l\n"; }
203 84c190b6 2021-12-17 jrmu # }
204 84c190b6 2021-12-17 jrmu #}
205 84c190b6 2021-12-17 jrmu #sub mforeach {
206 84c190b6 2021-12-17 jrmu # my ($bot, $nick, $host, $hand, $text) = @_;
207 84c190b6 2021-12-17 jrmu # if ($staff !~ /$nick/) { return; }
208 84c190b6 2021-12-17 jrmu # if ($text =~ /^network\s+del\s+([[:graph:]]+)\s+(#[[:graph:]]+)$/) {
209 84c190b6 2021-12-17 jrmu # my ($user, $chan) = ($1, $2);
210 84c190b6 2021-12-17 jrmu # foreach my $n (@main::networks) {
211 84c190b6 2021-12-17 jrmu # main::putserv($bot, "PRIVMSG *controlpanel :delchan $user $n->{name} $chan");
212 84c190b6 2021-12-17 jrmu # }
213 84c190b6 2021-12-17 jrmu # }
214 84c190b6 2021-12-17 jrmu #}
215 84c190b6 2021-12-17 jrmu
216 84c190b6 2021-12-17 jrmu #sub loadlog {
217 84c190b6 2021-12-17 jrmu # open(my $fh, '<', "$authlog") or die "Could not read file 'authlog' $!";
218 84c190b6 2021-12-17 jrmu # chomp(@logs = <$fh>);
219 84c190b6 2021-12-17 jrmu # close $fh;
220 84c190b6 2021-12-17 jrmu #}
221 84c190b6 2021-12-17 jrmu
222 84c190b6 2021-12-17 jrmu # return all lines matching a pattern
223 84c190b6 2021-12-17 jrmu #sub regex {
224 84c190b6 2021-12-17 jrmu # my ($pattern) = @_;
225 84c190b6 2021-12-17 jrmu # if (!@logs) { loadlog(); }
226 84c190b6 2021-12-17 jrmu # return grep(/$pattern/, @logs);
227 84c190b6 2021-12-17 jrmu #}
228 84c190b6 2021-12-17 jrmu
229 84c190b6 2021-12-17 jrmu # given a list of IPs, return matching users
230 84c190b6 2021-12-17 jrmu # or given a list of users, return matching IPs
231 84c190b6 2021-12-17 jrmu #sub regexlist {
232 84c190b6 2021-12-17 jrmu # my ($items) = @_;
233 84c190b6 2021-12-17 jrmu # my @items = split /[,\s]+/m, $items;
234 84c190b6 2021-12-17 jrmu # my $pattern = "(".join('|', @items).")";
235 84c190b6 2021-12-17 jrmu # if (!@logs) { loadlog(); }
236 84c190b6 2021-12-17 jrmu # my @matches = grep(/$pattern/, @logs);
237 84c190b6 2021-12-17 jrmu # my @results;
238 84c190b6 2021-12-17 jrmu # foreach my $match (@matches) {
239 84c190b6 2021-12-17 jrmu # if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
240 84c190b6 2021-12-17 jrmu # my ($user, $ip) = ($1, $3);
241 84c190b6 2021-12-17 jrmu # if ($items =~ /[.:]/) { # items are IP addresses
242 84c190b6 2021-12-17 jrmu # push(@results, $user);
243 84c190b6 2021-12-17 jrmu # } else { # items are users
244 84c190b6 2021-12-17 jrmu # push(@results, $ip);
245 84c190b6 2021-12-17 jrmu # }
246 84c190b6 2021-12-17 jrmu # }
247 84c190b6 2021-12-17 jrmu # }
248 84c190b6 2021-12-17 jrmu # my @sorted = sort @results;
249 84c190b6 2021-12-17 jrmu # @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
250 84c190b6 2021-12-17 jrmu # return join(' ', @results);
251 84c190b6 2021-12-17 jrmu #}
252 84c190b6 2021-12-17 jrmu
253 84c190b6 2021-12-17 jrmu sub createshell {
254 84c190b6 2021-12-17 jrmu my ($username, $password, $bindhost) = @_;
255 84c190b6 2021-12-17 jrmu system "doas groupadd $username";
256 84c190b6 2021-12-17 jrmu system "doas adduser -batch $username $username $username `encrypt $password`";
257 84c190b6 2021-12-17 jrmu system "doas chmod 700 /home/$username /home/$username/.ssh";
258 84c190b6 2021-12-17 jrmu system "doas chmod 600 /home/$username/{.Xdefaults,.cshrc,.cvsrc,.login,.mailrc,.profile}";
259 84c190b6 2021-12-17 jrmu system "doas mkdir /var/www/htdocs/$username";
260 84c190b6 2021-12-17 jrmu system "doas ln -s /var/www/htdocs/$username /home/$username/htdocs";
261 84c190b6 2021-12-17 jrmu system "doas chown -R $username:www /var/www/htdocs/$username /home/$username/htdocs";
262 84c190b6 2021-12-17 jrmu system "doas chmod -R o-rx /var/www/htdocs/$username /home/$username/htdocs";
263 84c190b6 2021-12-17 jrmu system "doas chmod -R g+rwx /var/www/htdocs/$username /home/$username/htdocs";
264 84c190b6 2021-12-17 jrmu my $lusername = lc $username;
265 84c190b6 2021-12-17 jrmu my $block = <<"EOF";
266 84c190b6 2021-12-17 jrmu server "$lusername.$hostname" {
267 84c190b6 2021-12-17 jrmu listen on * port 80
268 84c190b6 2021-12-17 jrmu location "/.well-known/acme-challenge/*" {
269 84c190b6 2021-12-17 jrmu root "/acme"
270 84c190b6 2021-12-17 jrmu request strip 2
271 84c190b6 2021-12-17 jrmu }
272 84c190b6 2021-12-17 jrmu location "*.php" {
273 84c190b6 2021-12-17 jrmu fastcgi socket "/run/php-fpm.sock"
274 84c190b6 2021-12-17 jrmu }
275 84c190b6 2021-12-17 jrmu root "/htdocs/$username"
276 84c190b6 2021-12-17 jrmu }
277 84c190b6 2021-12-17 jrmu EOF
278 84c190b6 2021-12-17 jrmu main::appendfile($httpdconfpath, $block);
279 84c190b6 2021-12-17 jrmu $block = <<"EOF";
280 84c190b6 2021-12-17 jrmu domain "$lusername.$hostname" {
281 84c190b6 2021-12-17 jrmu domain key "/etc/ssl/private/$lusername.$hostname.key"
282 84c190b6 2021-12-17 jrmu domain full chain certificate "/etc/ssl/$lusername.$hostname.crt"
283 84c190b6 2021-12-17 jrmu sign with letsencrypt
284 84c190b6 2021-12-17 jrmu }
285 84c190b6 2021-12-17 jrmu EOF
286 84c190b6 2021-12-17 jrmu main::appendfile($acmeconfpath, $block);
287 84c190b6 2021-12-17 jrmu configurepf($username);
288 84c190b6 2021-12-17 jrmu system "doas rcctl reload httpd";
289 84c190b6 2021-12-17 jrmu system "doas acme-client -F $lusername.$hostname";
290 84c190b6 2021-12-17 jrmu system "doas ln -s /etc/ssl/$lusername.$hostname.crt /etc/ssl/$lusername.$hostname.fullchain.pem";
291 84c190b6 2021-12-17 jrmu system "doas pfctl -f /etc/pf.conf";
292 84c190b6 2021-12-17 jrmu configurerelayd($username);
293 84c190b6 2021-12-17 jrmu $block = <<"EOF";
294 84c190b6 2021-12-17 jrmu ~ * * * * acme-client $lusername.$hostname && rcctl reload relayd
295 84c190b6 2021-12-17 jrmu EOF
296 84c190b6 2021-12-17 jrmu system "echo $block | doas crontab -";
297 84c190b6 2021-12-17 jrmu #edquota $username
298 84c190b6 2021-12-17 jrmu return 1;
299 84c190b6 2021-12-17 jrmu }
300 84c190b6 2021-12-17 jrmu
301 84c190b6 2021-12-17 jrmu sub deleteshell {
302 84c190b6 2021-12-17 jrmu my ($username, $bindhost) = @_;
303 84c190b6 2021-12-17 jrmu my $lusername = lc $username;
304 84c190b6 2021-12-17 jrmu system "doas groupdel $username";
305 84c190b6 2021-12-17 jrmu system "doas userdel $username";
306 84c190b6 2021-12-17 jrmu system "doas rm -f /etc/ssl/$lusername.$hostname.crt /etc/ssl/$lusername.$hostname.fullchain.pem /etc/ssl/private/$lusername.$hostname.key";
307 84c190b6 2021-12-17 jrmu my $httpdconf = main::readstr($httpdconfpath);
308 84c190b6 2021-12-17 jrmu my $block = <<"EOF";
309 84c190b6 2021-12-17 jrmu server "$lusername.$hostname" {
310 84c190b6 2021-12-17 jrmu listen on * port 80
311 84c190b6 2021-12-17 jrmu location "/.well-known/acme-challenge/*" {
312 84c190b6 2021-12-17 jrmu root "/acme"
313 84c190b6 2021-12-17 jrmu request strip 2
314 84c190b6 2021-12-17 jrmu }
315 84c190b6 2021-12-17 jrmu location "*.php" {
316 84c190b6 2021-12-17 jrmu fastcgi socket "/run/php-fpm.sock"
317 84c190b6 2021-12-17 jrmu }
318 84c190b6 2021-12-17 jrmu root "/htdocs/$username"
319 84c190b6 2021-12-17 jrmu }
320 84c190b6 2021-12-17 jrmu EOF
321 84c190b6 2021-12-17 jrmu $block =~ s/{/\\{/gm;
322 84c190b6 2021-12-17 jrmu $block =~ s/}/\\}/gm;
323 84c190b6 2021-12-17 jrmu $block =~ s/\./\\./gm;
324 84c190b6 2021-12-17 jrmu $block =~ s/\*/\\*/gm;
325 84c190b6 2021-12-17 jrmu $httpdconf =~ s{$block}{}gm;
326 84c190b6 2021-12-17 jrmu print $httpdconf;
327 84c190b6 2021-12-17 jrmu main::writefile($httpdconfpath, $httpdconf);
328 84c190b6 2021-12-17 jrmu
329 84c190b6 2021-12-17 jrmu my $acmeconf = main::readstr($acmeconfpath);
330 84c190b6 2021-12-17 jrmu $block = <<"EOF";
331 84c190b6 2021-12-17 jrmu domain "$lusername.$hostname" {
332 84c190b6 2021-12-17 jrmu domain key "/etc/ssl/private/$lusername.$hostname.key"
333 84c190b6 2021-12-17 jrmu domain full chain certificate "/etc/ssl/$lusername.$hostname.fullchain.pem"
334 84c190b6 2021-12-17 jrmu sign with letsencrypt
335 84c190b6 2021-12-17 jrmu }
336 84c190b6 2021-12-17 jrmu EOF
337 84c190b6 2021-12-17 jrmu $block =~ s/{/\\{/gm;
338 84c190b6 2021-12-17 jrmu $block =~ s/}/\\}/gm;
339 84c190b6 2021-12-17 jrmu $block =~ s/\./\\./gm;
340 84c190b6 2021-12-17 jrmu $block =~ s/\*/\\*/gm;
341 84c190b6 2021-12-17 jrmu $acmeconf =~ s{$block}{}gm;
342 84c190b6 2021-12-17 jrmu main::writefile($acmeconfpath, $acmeconf);
343 84c190b6 2021-12-17 jrmu return 1;
344 84c190b6 2021-12-17 jrmu }
345 84c190b6 2021-12-17 jrmu
346 84c190b6 2021-12-17 jrmu #TODO Fix for $i
347 84c190b6 2021-12-17 jrmu # Return column $i from $filename as an array with file separator $FS
348 84c190b6 2021-12-17 jrmu sub col {
349 84c190b6 2021-12-17 jrmu my ($filename, $i, $FS) = @_;
350 84c190b6 2021-12-17 jrmu my @rows = main::readarray($filename);
351 84c190b6 2021-12-17 jrmu my @results;
352 84c190b6 2021-12-17 jrmu foreach my $row (@rows) {
353 84c190b6 2021-12-17 jrmu if ($row =~ /^(.*?)$FS/) {
354 84c190b6 2021-12-17 jrmu push(@results, $1);
355 84c190b6 2021-12-17 jrmu }
356 84c190b6 2021-12-17 jrmu }
357 84c190b6 2021-12-17 jrmu return @results;
358 84c190b6 2021-12-17 jrmu }
359 84c190b6 2021-12-17 jrmu
360 84c190b6 2021-12-17 jrmu sub configurepf {
361 84c190b6 2021-12-17 jrmu my $username = shift;
362 84c190b6 2021-12-17 jrmu my @read = split('\n', main::readstr($pfconfpath) );
363 84c190b6 2021-12-17 jrmu
364 84c190b6 2021-12-17 jrmu my $previousline = "";
365 84c190b6 2021-12-17 jrmu my @pfcontent;
366 84c190b6 2021-12-17 jrmu foreach my $line(@read)
367 84c190b6 2021-12-17 jrmu {
368 84c190b6 2021-12-17 jrmu my $currline = $line;
369 84c190b6 2021-12-17 jrmu if( $currline ne "# end user ports") {
370 84c190b6 2021-12-17 jrmu $previousline = $currline;
371 84c190b6 2021-12-17 jrmu } else {
372 84c190b6 2021-12-17 jrmu #pass in proto {tcp udp} to port {31361:31370} user {JL}
373 84c190b6 2021-12-17 jrmu if( $previousline =~ /(\d*):(\d*)/ ) {
374 84c190b6 2021-12-17 jrmu my $startport = ( $1 + 10 );
375 84c190b6 2021-12-17 jrmu my $endport = ( $2 + 10 );
376 84c190b6 2021-12-17 jrmu my $insert = "pass in proto {tcp udp} to port {$startport:$endport} user {$username}";
377 84c190b6 2021-12-17 jrmu push(@pfcontent, $insert);
378 84c190b6 2021-12-17 jrmu $startPort = $startport;
379 84c190b6 2021-12-17 jrmu $endPort = $endport;
380 84c190b6 2021-12-17 jrmu }
381 84c190b6 2021-12-17 jrmu }
382 84c190b6 2021-12-17 jrmu push(@pfcontent, $currline)
383 84c190b6 2021-12-17 jrmu }
384 84c190b6 2021-12-17 jrmu main::writefile("$pfconfpath", join("\n",@pfcontent))
385 84c190b6 2021-12-17 jrmu }
386 84c190b6 2021-12-17 jrmu
387 84c190b6 2021-12-17 jrmu sub configurerelayd {
388 84c190b6 2021-12-17 jrmu my ($username) = @_;
389 84c190b6 2021-12-17 jrmu my $block = "tls { keypair $username.$hostname }";
390 84c190b6 2021-12-17 jrmu my $relaydconf = main::readstr($relaydconfpath);
391 84c190b6 2021-12-17 jrmu my $newconf;
392 84c190b6 2021-12-17 jrmu if ($relaydconf =~ /^.*tls\s+{\s+keypair\s+[.0-9a-zA-Z]+\s*}/m) {
393 84c190b6 2021-12-17 jrmu $newconf = "$`$&\n\t$block$'";
394 84c190b6 2021-12-17 jrmu }
395 84c190b6 2021-12-17 jrmu main::writefile($relaydconfpath, $newconf);
396 84c190b6 2021-12-17 jrmu }
397 84c190b6 2021-12-17 jrmu
398 84c190b6 2021-12-17 jrmu #unveil("./newacct", "rx") or die "Unable to unveil $!";
399 84c190b6 2021-12-17 jrmu 1; # MUST BE LAST STATEMENT IN FILE