From: Matt Birkholz Date: Wed, 8 May 2024 20:43:00 +0000 (-0600) Subject: Update README.html. X-Git-Url: https://birchwood-abbey.net/git?a=commitdiff_plain;ds=sidebyside;p=Institute Update README.html. --- diff --git a/README.html b/README.html index 2adc81a..342fbbd 100644 --- a/README.html +++ b/README.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + A Small Institute @@ -48,7 +48,7 @@ connects to Front making the institute email, cloud, etc. available to members off campus.

-
+
                 =                                                   
               _|||_                                                 
         =-The-Institute-=                                           
@@ -1022,7 +1022,7 @@ example result follows the code.
 
-
+

=> 10.62.17.0/24

@@ -1475,7 +1475,7 @@ USB-Ethernet adapter, or a wireless adapter connected to a campground Wi-Fi access point, etc. -
+
 =============== | ==================================================
                 |                                           Premises
           (Campus ISP)                                              
@@ -1498,7 +1498,7 @@ This avoids the need for a second Wi-Fi access point and leads to the
 following topology.
 

-
+
 =============== | ==================================================
                 |                                           Premises
            (House ISP)                                              
@@ -1651,8 +1651,8 @@ The all role contains tasks that are executed on all of the
 institute's servers.  At the moment there is just the one.
 

-
-

6.1. Include Particulars

+
+

6.1. Include Particulars

The all role's task contains a reference to a common institute @@ -1793,8 +1793,8 @@ uses the institute's CA and server certificates, and expects client certificates signed by the institute CA.

-
-

7.1. Include Particulars

+
+

7.1. Include Particulars

The first task, as in The All Role, is to include the institute @@ -1819,8 +1819,8 @@ membership roll, so these are included was well.

-
-

7.2. Configure Hostname

+
+

7.2. Configure Hostname

This task ensures that Front's /etc/hostname and /etc/mailname are @@ -1850,8 +1850,8 @@ delivery.

-
-

7.3. Add Administrator to System Groups

+
+

7.3. Add Administrator to System Groups

The administrator often needs to read (directories of) log files owned @@ -1910,8 +1910,8 @@ those stored in Secret/ssh_front/etc/ssh/

-
-

7.5. Configure Monkey

+
+

7.5. Configure Monkey

The small institute runs cron jobs and web scripts that generate @@ -1967,8 +1967,8 @@ Monkey uses Rsync to keep the institute's public web site up-to-date.

-
-

7.7. Install Unattended Upgrades

+
+

7.7. Install Unattended Upgrades

The institute prefers to install security updates as soon as possible. @@ -1983,8 +1983,8 @@ The institute prefers to install security updates as soon as possible.

-
-
-

7.9. Install Server Certificate

+
+

7.9. Install Server Certificate

The servers on Front use the same certificate (and key) to @@ -2255,8 +2255,8 @@ created by a more specialized role.

-
-

7.12. Configure Dovecot IMAPd

+
+

7.12. Configure Dovecot IMAPd

Front uses Dovecot's IMAPd to allow user Fetchmail jobs on Core to @@ -2612,8 +2612,8 @@ the users' ~/Public/HTML/ directories.

-
-

7.14. Configure OpenVPN

+
+

7.14. Configure OpenVPN

Front uses OpenVPN to provide the institute's public VPN service. The @@ -2896,8 +2896,8 @@ Debian install and remote access to a privileged, administrator's account. (For details, see The Core Machine.)

-
-

8.1. Include Particulars

+
+

8.1. Include Particulars

The first task, as in The Front Role, is to include the institute @@ -2919,8 +2919,8 @@ particulars and membership roll.

-
-

8.2. Configure Hostname

+
+

8.2. Configure Hostname

This task ensures that Core's /etc/hostname and /etc/mailname are @@ -2953,8 +2953,8 @@ proper email delivery.

-
-

8.3. Configure Systemd Resolved

+
+

8.3. Configure Systemd Resolved

Core runs the campus name server, so Resolved is configured to use it @@ -3367,8 +3367,8 @@ probably be used as forwarders rather than Google.

-
-

8.7. Add Administrator to System Groups

+
+

8.7. Add Administrator to System Groups

The administrator often needs to read (directories of) log files owned @@ -3388,8 +3388,8 @@ these groups speeds up debugging.

-
-

8.8. Configure Monkey

+
+

8.8. Configure Monkey

The small institute runs cron jobs and web scripts that generate @@ -3456,8 +3456,8 @@ described in *Configure Apache2).

-
-

8.9. Install Unattended Upgrades

+
+

8.9. Install Unattended Upgrades

The institute prefers to install security updates as soon as possible. @@ -3489,8 +3489,8 @@ with Nextcloud on the command line.

-
-

8.11. Configure User Accounts

+
+

8.11. Configure User Accounts

User accounts are created immediately so that backups can begin @@ -3532,8 +3532,8 @@ describes the members and usernames variables.

-
-

8.12. Install Server Certificate

+
+

8.12. Install Server Certificate

The servers on Core use the same certificate (and key) to authenticate @@ -3757,8 +3757,8 @@ installed by more specialized roles.

-
-

8.16. Configure Dovecot IMAPd

+
+

8.16. Configure Dovecot IMAPd

Core uses Dovecot's IMAPd to store and serve member emails. As on @@ -4157,22 +4157,11 @@ The tasks below install Apache2 and edit its default configuration. apt: pkg=apache2 - name: Enable Apache2 modules. - become: yes - apache2_module: - name: "{{ item }}" - loop: [ userdir, cgi ] - notify: Restart Apache2. - when: ansible_distribution != 'Debian' - or 12 > ansible_distribution_major_version|int - -- name: Enable Apache2 modules (Debian 12). become: yes apache2_module: name: "{{ item }}" loop: [ userdir, cgid ] notify: Restart Apache2. - when: ansible_distribution == 'Debian' - and 11 < ansible_distribution_major_version|int

@@ -5091,22 +5080,11 @@ performance, as recommended by Nextcloud.
roles_t/core/tasks/main.yml
 - name: Set PHP memory_limit for Nextcloud.
-  become: yes
-  lineinfile:
-    path: /etc/php/7.4/apache2/php.ini
-    regexp: memory_limit *=
-    line: memory_limit = 512M
-  when: ansible_distribution != 'Debian'
-        or 12 > ansible_distribution_major_version|int
-
-- name: Set PHP memory_limit for Nextcloud (Debian 12).
   become: yes
   lineinfile:
     path: /etc/php/8.2/apache2/php.ini
     regexp: memory_limit *=
     line: memory_limit = 512M
-  when: ansible_distribution == 'Debian'
-        and 11 < ansible_distribution_major_version|int
 
 - name: Include PHP parameters for Nextcloud.
   become: yes
@@ -5116,12 +5094,12 @@ performance, as recommended by Nextcloud.
       apc.enable_cli=1
       opcache.enable=1
       opcache.enable_cli=1
-      opcache.interned_strings_buffer=8
+      opcache.interned_strings_buffer=12
       opcache.max_accelerated_files=10000
       opcache.memory_consumption=128
       opcache.save_comments=1
       opcache.revalidate_freq=1
-    dest: /etc/php/7.4/mods-available/nextcloud.ini
+    dest: /etc/php/8.2/mods-available/nextcloud.ini
   notify: Restart Apache2.
 
 - name: Enable Nextcloud PHP modules.
@@ -5530,8 +5508,8 @@ applied first, by which Gate gets a campus machine's DNS and Postfix
 configurations, etc.
 

-
-

9.1. Include Particulars

+
+

9.1. Include Particulars

The following should be familiar boilerplate by now. @@ -5900,8 +5878,8 @@ the daemon listens only on the Gate-WiFi network interface.

-
-

9.6. Install Server Certificate

+
+

9.6. Install Server Certificate

The (OpenVPN) server on Gate uses an institute certificate (and key) @@ -5928,8 +5906,8 @@ and Front) do.

-
-

9.7. Configure OpenVPN

+
+

9.7. Configure OpenVPN

Gate uses OpenVPN to provide the institute's campus VPN service. Its @@ -6056,8 +6034,8 @@ Wireless campus devices can get a key to the campus VPN from the configured manually.

-
-

10.1. Include Particulars

+
+

10.1. Include Particulars

The following should be familiar boilerplate by now. @@ -6073,8 +6051,8 @@ The following should be familiar boilerplate by now.

-
-

10.2. Configure Hostname

+
+

10.2. Configure Hostname

Clients should be using the expected host name. @@ -6101,8 +6079,8 @@ Clients should be using the expected host name.

-
-

10.3. Configure Systemd Resolved

+
+

10.3. Configure Systemd Resolved

Campus machines use the campus name server on Core (or dns.google), @@ -6173,8 +6151,8 @@ and file timestamps.

-
-

10.5. Add Administrator to System Groups

+
+

10.5. Add Administrator to System Groups

The administrator often needs to read (directories of) log files owned @@ -6194,8 +6172,8 @@ these groups speeds up debugging.

-
-

10.6. Install Unattended Upgrades

+
+

10.6. Install Unattended Upgrades

The institute prefers to install security updates as soon as possible. @@ -6675,8 +6653,8 @@ The first code block is the header of the ./inst script. # # DO NOT EDIT. This file was tangled from an institute.org file. -use strict; -use IO::File; +use strict; +use IO::File;

@@ -6699,7 +6677,7 @@ permissions. It probes past the Secret/ mount poin sub note_missing_directory_p ($); { - my $missing = 0; + my $missing = 0; if (note_missing_file_p "ansible.cfg") { $missing += 1; } if (note_missing_file_p "hosts") { $missing += 1; } if (note_missing_directory_p "Secret") { $missing += 1; } @@ -6710,8 +6688,8 @@ permissions. It probes past the Secret/ mount poin if (note_missing_directory_p "public") { $missing += 1; } if (note_missing_directory_p "private") { $missing += 1; } - for my $filename (glob "private/*") { - my $perm = (stat $filename)[2]; + for my $filename (glob "private/*") { + my $perm = (stat $filename)[2]; if ($perm & 077) { print "$filename: not private\n"; } @@ -6720,7 +6698,7 @@ permissions. It probes past the Secret/ mount poin } sub note_missing_file_p ($) { - my ($filename) = @_; + my ($filename) = @_; if (! -f $filename) { print "$filename: missing\n"; return 1; @@ -6730,7 +6708,7 @@ permissions. It probes past the Secret/ mount poin } sub note_missing_directory_p ($) { - my ($dirname) = @_; + my ($dirname) = @_; if (! -d $dirname) { print "$dirname: missing\n"; return 1; @@ -6845,7 +6823,7 @@ config.
inst
 if (defined $ARGV[0] && $ARGV[0] eq "CA") {
-  die "usage: $0 CA" if @ARGV != 1;
+  die "usage: $0 CA" if @ARGV != 1;
   die "Secret/CA/easyrsa: not an executable\n"
     if ! -x "Secret/CA/easyrsa";
   die "Secret/CA/pki/: already exists\n" if -e "Secret/CA/pki";
@@ -6855,8 +6833,8 @@ config.
   mysystem "cd Secret/CA; ./easyrsa build-ca nopass";
   # Common Name: small.example.org
 
-  my $dom = $domain_name;
-  my $pvt = $domain_priv;
+  my $dom = $domain_name;
+  my $pvt = $domain_priv;
   mysystem "cd Secret/CA; ./easyrsa build-server-full $dom nopass";
   mysystem "cd Secret/CA; ./easyrsa build-server-full gate.$pvt nopass";
   mysystem "cd Secret/CA; ./easyrsa build-server-full core.$pvt nopass";
@@ -6930,15 +6908,15 @@ Example command lines:
   die "Secret/CA/easyrsa: not executable\n"
     if ! -x "Secret/CA/easyrsa";
   shift;
-  my $cmd = "ansible-playbook -e \@Secret/become.yml";
+  my $cmd = "ansible-playbook -e \@Secret/become.yml";
   if (defined $ARGV[0] && $ARGV[0] eq "-n") {
     shift;
     $cmd .= " --check --diff"
   }
-  if (@ARGV == 0) {
+  if (@ARGV == 0) {
     ;
   } elsif (defined $ARGV[0]) {
-    my $hosts = lc $ARGV[0];
+    my $hosts = lc $ARGV[0];
     die "$hosts: contains illegal characters"
       if $hosts !~ /^!?[a-z][-a-z0-9,!]+$/;
     $cmd .= " -l $hosts";
@@ -7045,10 +7023,10 @@ read from the file.  The dump subroutine is another story (below).
 
 
inst
-use YAML::XS qw(LoadFile DumpFile);
+use YAML::XS qw(LoadFile DumpFile);
 
 sub read_members_yaml () {
-  my $path;
+  my $path;
   $path = "private/members.yml";
   if (-e $path) { return LoadFile ($path); }
   $path = "private/members-empty.yml";
@@ -7057,15 +7035,15 @@ read from the file.  The dump subroutine is another story (below).
 }
 
 sub write_members_yaml ($) {
-  my ($yaml) = @_;
-  my $old_umask = umask 077;
-  my $path = "private/members.yml";
+  my ($yaml) = @_;
+  my $old_umask = umask 077;
+  my $path = "private/members.yml";
   print "$path: "; STDOUT->flush;
   eval { #DumpFile ("$path.tmp", $yaml);
          dump_members_yaml ("$path.tmp", $yaml);
          rename ("$path.tmp", $path)
            or die "Could not rename $path.tmp: $!\n"; };
-  my $err = $@;
+  my $err = $@;
   umask $old_umask;
   if ($err) {
     print "ERROR\n";
@@ -7076,17 +7054,17 @@ read from the file.  The dump subroutine is another story (below).
 }
 
 sub dump_members_yaml ($$) {
-  my ($pathname, $yaml) = @_;
-  my $O = new IO::File;
+  my ($pathname, $yaml) = @_;
+  my $O = new IO::File;
   open ($O, ">$pathname") or die "Could not open $pathname: $!\n";
   print $O "---\n";
   if (keys %{$yaml->{"members"}}) {
     print $O "members:\n";
-    for my $user (sort keys %{$yaml->{"members"}}) {
+    for my $user (sort keys %{$yaml->{"members"}}) {
       print_member ($O, $yaml->{"members"}->{$user});
     }
     print $O "usernames:\n";
-    for my $user (sort keys %{$yaml->{"members"}}) {
+    for my $user (sort keys %{$yaml->{"members"}}) {
       print $O "- $user\n";
     }
   } else {
@@ -7095,7 +7073,7 @@ read from the file.  The dump subroutine is another story (below).
   }
   if (@{$yaml->{"revoked"}}) {
     print $O "revoked:\n";
-    for my $name (@{$yaml->{"revoked"}}) {
+    for my $name (@{$yaml->{"revoked"}}) {
       print $O "- $name\n";
     }
   } else {
@@ -7122,13 +7100,13 @@ each record.
 
inst
 sub print_member ($$) {
-  my ($out, $member) = @_;
+  my ($out, $member) = @_;
   print $out "  ", $member->{"username"}, ":\n";
   print $out "    username: ", $member->{"username"}, "\n";
   print $out "    status: ", $member->{"status"}, "\n";
   if (@{$member->{"clients"} || []}) {
     print $out "    clients:\n";
-    for my $name (@{$member->{"clients"} || []}) {
+    for my $name (@{$member->{"clients"} || []}) {
       print $out "    - ", $name, "\n";
     }
   } else {
@@ -7138,18 +7116,18 @@ each record.
   print $out "    password_core: ", $member->{"password_core"}, "\n";
   if (defined $member->{"password_fetchmail"}) {
     print $out "    password_fetchmail: !vault |\n";
-    for my $line (split /\n/, $member->{"password_fetchmail"}) {
+    for my $line (split /\n/, $member->{"password_fetchmail"}) {
       print $out "      $line\n";
     }
   }
-  my @standard_keys = ( "username", "status", "clients",
+  my @standard_keys = ( "username", "status", "clients",
                         "password_front", "password_core",
                         "password_fetchmail" );
-  my @other_keys = (sort
-                    grep { my $k = $_;
-                           ! grep { $_ eq $k } @standard_keys }
+  my @other_keys = (sort
+                    grep { my $k = $_;
+                           ! grep { $_ eq $k } @standard_keys }
                     keys %$member);
-  for my $key (@other_keys) {
+  for my $key (@other_keys) {
     print $out "    $key: ", $member->{$key}, "\n";
   }
 }
@@ -7178,17 +7156,17 @@ initial, generated password.
 sub strip_vault ($);
 
 if (defined $ARGV[0] && $ARGV[0] eq "new") {
-  my $user = valid_username (@ARGV);
-  my $yaml = read_members_yaml ();
-  my $members = $yaml->{"members"};
+  my $user = valid_username (@ARGV);
+  my $yaml = read_members_yaml ();
+  my $members = $yaml->{"members"};
   die "$user: already exists\n" if defined $members->{$user};
 
-  my $pass = `apg -n 1 -x 12 -m 12`; chomp $pass;
+  my $pass = `apg -n 1 -x 12 -m 12`; chomp $pass;
   print "Initial password: $pass\n";
-  my $epass = shell_escape $pass;
-  my $front = `mkpasswd -m sha-512 "$epass"`; chomp $front;
-  my $core = `mkpasswd -m sha-512 "$epass"`; chomp $core;
-  my $vault = strip_vault `ansible-vault encrypt_string "$epass"`;
+  my $epass = shell_escape $pass;
+  my $front = `mkpasswd -m sha-512 "$epass"`; chomp $front;
+  my $core = `mkpasswd -m sha-512 "$epass"`; chomp $core;
+  my $vault = strip_vault `ansible-vault encrypt_string "$epass"`;
   mysystem ("ansible-playbook -e \@Secret/become.yml",
             " playbooks/nextcloud-new.yml",
             " -e user=$user", " -e pass=\"$epass\"");
@@ -7206,10 +7184,10 @@ initial, generated password.
 }
 
 sub valid_username (@) {
-  my $sub = $_[0];
+  my $sub = $_[0];
   die "usage: $0 $sub USER\n"
-    if @_ != 2;
-  my $username = lc $_[1];
+    if @_ != 2;
+  my $username = lc $_[1];
   die "$username: does not begin with an alphabetic character\n"
     if $username !~ /^[a-z]/;
   die "$username: contains non-alphanumeric character(s)\n"
@@ -7218,18 +7196,18 @@ initial, generated password.
 }
 
 sub shell_escape ($) {
-  my ($string) = @_;
-  my $result = "$string";
+  my ($string) = @_;
+  my $result = "$string";
   $result =~ s/([\$`"\\ ])/\\$1/g;
   return ($result);
 }
 
 sub strip_vault ($) {
-  my ($string) = @_;
+  my ($string) = @_;
   die "Unexpected result from ansible-vault: $string\n"
     if $string !~ /^ *!vault [|]/;
-  my @lines = split /^ */m, $string;
-  return (join "", @lines[1..$#lines]);
+  my @lines = split /^ */m, $string;
+  return (join "", @lines[1..$#lines]);
 }
 
@@ -7294,11 +7272,11 @@ in Secret/.
roles_t/core/templates/passwd
#!/bin/perl -wT
 
-use strict;
+use strict;
 
 $ENV{PATH} = "/usr/sbin:/usr/bin:/bin";
 
-my ($username) = getpwuid $<;
+my ($username) = getpwuid $<;
 if ($username ne "{{ ansible_user }}") {
   { exec ("sudo", "-u", "{{ ansible_user }}",
           "/usr/local/bin/passwd", $username) };
@@ -7307,11 +7285,11 @@ $ENV{PATH} = "/u
 }
 
 $username = $ARGV[0];
-my $passwd;
+my $passwd;
 {
-  my $SHADOW = new IO::File;
+  my $SHADOW = new IO::File;
   open $SHADOW, "</etc/shadow" or die "Cannot read /etc/shadow: $!\n";
-  my ($line) = grep /^$username:/, <$SHADOW>;
+  my ($line) = grep /^$username:/, <$SHADOW>;
   close $SHADOW;
   die "No /etc/shadow record found: $username\n" if ! defined $line;
   (undef, $passwd) = split ":", $line;
@@ -7321,9 +7299,9 @@ system "stty -echo";
 END { system "stty echo"; }
 
 print "Current password: ";
-my $pass = <STDIN>; chomp $pass;
+my $pass = <STDIN>; chomp $pass;
 print "\n";
-my $hash = crypt($pass, $passwd);
+my $hash = crypt($pass, $passwd);
 die "Sorry...\n" if $hash ne $passwd;
 
 print "New password: ";
@@ -7331,36 +7309,36 @@ $pass = <ST
 die "Passwords must be at least 10 characters long.\n"
   if length $pass < 10;
 print "\nRetype password: ";
-my $pass2 = <STDIN>; chomp($pass2);
+my $pass2 = <STDIN>; chomp($pass2);
 print "\n";
 die "New passwords do not match!\n"
   if $pass2 ne $pass;
 
-use MIME::Base64;
-my $epass = encode_base64 $pass;
+use MIME::Base64;
+my $epass = encode_base64 $pass;
 
-use File::Temp qw(tempfile);
-my ($TMP, $tmp) = tempfile;
+use File::Temp qw(tempfile);
+my ($TMP, $tmp) = tempfile;
 close $TMP;
 
-my $O = new IO::File;
+my $O = new IO::File;
 open $O, ("| gpg --encrypt --armor"
           ." --trust-model always --recipient root\@core"
           ." > $tmp") or die "Error running gpg > $tmp: $!\n";
 print $O <<EOD;
-username: $username
-password: $epass
-EOD
+username: $username
+password: $epass
+EOD
 close $O or die "Error closing pipe to gpg: $!\n";
 
-use File::Copy;
+use File::Copy;
 open ($O, "| sendmail root");
 print $O <<EOD;
-From: root
-To: root
-Subject: New password.
+From: root
+To: root
+Subject: New password.
 
-EOD
+EOD
 $O->flush;
 copy $tmp, $O;
 #print $O `cat $tmp`;
@@ -7385,32 +7363,32 @@ the administrator to update private/members.yml before running
 
 
inst
-use MIME::Base64;
+use MIME::Base64;
 
 if (defined $ARGV[0] && $ARGV[0] eq "pass") {
-  my $I = new IO::File;
+  my $I = new IO::File;
   open $I, "gpg --homedir Secret/root.gnupg --quiet --decrypt |"
     or die "Error running gpg: $!\n";
-  my $msg_yaml = LoadFile ($I);
+  my $msg_yaml = LoadFile ($I);
   close $I or die "Error closing pipe from gpg: $!\n";
 
-  my $user = $msg_yaml->{"username"};
+  my $user = $msg_yaml->{"username"};
   die "Could not find a username in the decrypted input.\n"
     if ! defined $user;
-  my $pass64 = $msg_yaml->{"password"};
+  my $pass64 = $msg_yaml->{"password"};
   die "Could not find a password in the decrypted input.\n"
     if ! defined $pass64;
 
-  my $mem_yaml = read_members_yaml ();
-  my $members = $mem_yaml->{"members"};
-  my $member = $members->{$user};
+  my $mem_yaml = read_members_yaml ();
+  my $members = $mem_yaml->{"members"};
+  my $member = $members->{$user};
   die "No such member: $user\n" if ! defined $member;
 
-  my $pass = decode_base64 $pass64;
-  my $epass = shell_escape $pass;
-  my $front = `mkpasswd -m sha-512 "$epass"`; chomp $front;
-  my $core = `mkpasswd -m sha-512 "$epass"`; chomp $core;
-  my $vault = strip_vault `ansible-vault encrypt_string "$epass"`;
+  my $pass = decode_base64 $pass64;
+  my $epass = shell_escape $pass;
+  my $front = `mkpasswd -m sha-512 "$epass"`; chomp $front;
+  my $core = `mkpasswd -m sha-512 "$epass"`; chomp $core;
+  my $vault = strip_vault `ansible-vault encrypt_string "$epass"`;
   $member->{"password_front"} = $front;
   $member->{"password_core"} = $core;
   $member->{"password_fetchmail"} = $vault;
@@ -7421,7 +7399,7 @@ the administrator to update private/members.yml before running
   write_members_yaml $mem_yaml;
   mysystem ("ansible-playbook -e \@Secret/become.yml",
             "-t accounts playbooks/site.yml");
-  my $O = new IO::File;
+  my $O = new IO::File;
   open ($O, "| sendmail $user\@$domain_priv")
     or die "Could not pipe to sendmail: $!\n";
   print $O "From: <root>
@@ -7551,10 +7529,10 @@ The old command disables a member's accounts and clients.
 
inst
 if (defined $ARGV[0] && $ARGV[0] eq "old") {
-  my $user = valid_username (@ARGV);
-  my $yaml = read_members_yaml ();
-  my $members = $yaml->{"members"};
-  my $member = $members->{$user};
+  my $user = valid_username (@ARGV);
+  my $yaml = read_members_yaml ();
+  my $members = $yaml->{"members"};
+  my $member = $members->{$user};
   die "$user: does not exist\n" if ! defined $member;
 
   mysystem ("ansible-playbook -e \@Secret/become.yml",
@@ -7648,29 +7626,29 @@ up-restart
 
 if (defined $ARGV[0] && $ARGV[0] eq "client") {
   die "Secret/CA/easyrsa: not found\n" if ! -x "Secret/CA/easyrsa";
-  my $type = $ARGV[1]||"";
-  my $name = $ARGV[2]||"";
-  my $user = $ARGV[3]||"";
+  my $type = $ARGV[1]||"";
+  my $name = $ARGV[2]||"";
+  my $user = $ARGV[3]||"";
   if ($type eq "campus") {
-    die "usage: $0 client campus NAME\n" if @ARGV != 3;
+    die "usage: $0 client campus NAME\n" if @ARGV != 3;
     die "$name: invalid host name\n" if $name !~ /^[a-z][-a-z0-9]+$/;
   } elsif ($type eq "android" || $type eq "debian") {
-    die "usage: $0 client $type NAME USER\n" if @ARGV != 4;
+    die "usage: $0 client $type NAME USER\n" if @ARGV != 4;
     die "$name: invalid host name\n" if $name !~ /^[a-z][-a-z0-9]+$/;
   } else {
-    die "usage: $0 client [debian|android|campus]\n" if @ARGV != 4;
+    die "usage: $0 client [debian|android|campus]\n" if @ARGV != 4;
   }
-  my $yaml;
-  my $member;
+  my $yaml;
+  my $member;
   if ($type ne "campus") {
     $yaml = read_members_yaml;
-    my $members = $yaml->{"members"};
-    if (@ARGV == 4) {
+    my $members = $yaml->{"members"};
+    if (@ARGV == 4) {
       $member = $members->{$user};
       die "$user: does not exist\n" if ! defined $member;
     }
     if (defined $member) {
-      my ($owner) = grep { grep { $_ eq $name } @{$_->{"clients"}} }
+      my ($owner) = grep { grep { $_ eq $name } @{$_->{"clients"}} }
                     values %{$members};
       die "$name: owned by $owner->{username}\n"
         if defined $owner && $owner->{username} ne $member->{username};
@@ -7687,7 +7665,7 @@ up-restart
   }
 
   if ($type ne "campus") {
-    my $clients = $member->{"clients"};
+    my $clients = $member->{"clients"};
     if (! grep { $_ eq $name } @$clients) {
       $member->{"clients"} = [ $name, @$clients ];
       write_members_yaml $yaml;
@@ -7695,20 +7673,20 @@ up-restart
   }
 
   umask 077;
-  my $DEV = $type eq "android" ? "tun" : "ovpn";
-  my $CA = read_file "Secret/CA/pki/ca.crt";
-  my $CRT = read_file "Secret/CA/pki/issued/$name.crt";
-  my $KEY = read_file "Secret/CA/pki/private/$name.key";
-  my $UP = $type eq "android" ? "" : "
+  my $DEV = $type eq "android" ? "tun" : "ovpn";
+  my $CA = read_file "Secret/CA/pki/ca.crt";
+  my $CRT = read_file "Secret/CA/pki/issued/$name.crt";
+  my $KEY = read_file "Secret/CA/pki/private/$name.key";
+  my $UP = $type eq "android" ? "" : "
 <<openvpn-up>>";
 
   if ($type ne "campus") {
-    my $TA = read_file "Secret/front-ta.key";
+    my $TA = read_file "Secret/front-ta.key";
     write_template ($DEV,$UP,$CA,$CRT,$KEY,$TA, $front_addr,
                     $domain_name, "public.ovpn");
     print "Wrote public VPN configuration to public.ovpn.\n";
   }
-  my $TA = read_file "Secret/gate-ta.key";
+  my $TA = read_file "Secret/gate-ta.key";
   write_template ($DEV,$UP,$CA,$CRT,$KEY,$TA, $gate_wifi_addr,
                   "gate.$domain_priv", "campus.ovpn");
   print "Wrote campus VPN configuration to campus.ovpn.\n";
@@ -7717,8 +7695,8 @@ up-restart
 }
 
 sub write_template ($$$$$$$$$) {
-  my ($DEV,$UP,$CA,$CRT,$KEY,$TA,$ADDR,$NAME,$FILE) = @_;
-  my $O = new IO::File;
+  my ($DEV,$UP,$CA,$CRT,$KEY,$TA,$ADDR,$NAME,$FILE) = @_;
+  my $O = new IO::File;
   open ($O, ">$FILE.tmp") or die "Could not open $FILE.tmp: $!\n";
   print $O "client
 dev-type tun
@@ -7741,11 +7719,11 @@ up-restart
 }
 
 sub read_file ($) {
-  my ($path) = @_;
-  my $I = new IO::File;
+  my ($path) = @_;
+  my $I = new IO::File;
   open ($I, "<$path") or die "$path: could not read: $!\n";
-  local $/;
-  my $c = <$I>;
+  local $/;
+  my $c = <$I>;
   close $I or die "$path: could not close: $!\n";
   return $c;
 }
@@ -8511,8 +8489,8 @@ require several more).
 
 
sudo apt install network-manager-openvpn-gnome \
-		 openvpn-systemd-resolved \
-		 nextcloud-desktop evolution
+                 openvpn-systemd-resolved \
+                 nextcloud-desktop evolution
 
@@ -9130,7 +9108,7 @@ routes on Front and Gate, making the simulation less… similar.

Author: Matt Birkholz

-

Created: 2024-05-03 Fri 10:44

+

Created: 2024-05-08 Wed 14:42

Validate