Blob


1 #!/usr/bin/perl
3 use strict;
4 use warnings;
5 use OpenBSD::Pledge;
6 use OpenBSD::Unveil;
7 use Data::Dumper;
8 use File::Copy qw(copy);
10 my $vmconf = "/etc/vm.conf";
11 my $zonedir = "/var/nsd/zones/master/";
12 my $hostname = "host.oddprotocol.org";
13 my $ipv4path = "/home/error/ipv4s";
14 my @ipv4s;
15 if (!(-s "$ipv4path")) {
16 print "No IPv4 addresses in $ipv4path!\n";
17 die;
18 } else {
19 @ipv4s = readarray($ipv4path);
20 }
22 `doas chmod -R g+w $zonedir`;
24 # Read from filename and return array of lines without trailing newlines
25 sub readarray {
26 my ($filename) = @_;
27 open(my $fh, '<', $filename) or die "Could not read file '$filename' $!";
28 chomp(my @lines = <$fh>);
29 close $fh;
30 return @lines;
31 }
33 # Read from filename and return as string
34 sub readstr {
35 my ($filename) = @_;
36 open my $fh, '<', $filename or die "Could not read file '$filename' $!";
37 my $str = do { local $/; <$fh> };
38 close $fh;
39 return $str;
40 }
42 # Write str to filename
43 sub writefile {
44 my ($filename, $str) = @_;
45 open(my $fh, '>', "$filename") or die "Could not write to $filename";
46 print $fh $str;
47 close $fh;
48 }
50 # Append str to filename
51 sub appendfile {
52 my ($filename, $str) = @_;
53 open(my $fh, '>>', "$filename") or die "Could not append to $filename";
54 print $fh $str;
55 close $fh;
56 }
58 sub date {
59 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
60 my $localtime = sprintf("%04d%02d%02d", $year+1900, $mon+1, $mday);
61 return $localtime;
62 }
64 sub setdns {
65 my ($domain, $ip) = @_;
66 my $filename = "$zonedir/$hostname";
67 my $subdomain;
68 if ($domain =~ /^([a-zA-Z][-\.a-zA-Z0-9]+)\.$hostname$/) {
69 $subdomain = $1;
70 } else {
71 return 0;
72 }
73 my @lines = readarray($filename);
74 foreach my $line (@lines) {
75 # increment the zone's serial number
76 if ($line =~ /(\d{8})(\d{2})((\s+\d+){4}\s*\))/) {
77 my $date = date();
78 my $serial = 0;
79 if ($date <= $1) { $serial = $2+1; }
80 $line = $`.$date.sprintf("%02d",$serial).$3.$';
81 }
82 }
83 if ($ip =~ /^([0-9\.]+)$/) { # if IPv4
84 push(@lines, "$subdomain 3600 IN A $ip");
85 } elsif ($ip =~ /:/) { # if IPv6
86 push(@lines, "$subdomain 3600 IN AAAA $ip");
87 } elsif (!defined($ip)) { # delete records
88 @lines = grep !/\b$subdomain\s*3600\s*IN/, @lines;
89 }
90 # trailing newline necessary
91 writefile("$filename.bak", join("\n", @lines)."\n");
92 copy "$filename.bak", $filename;
93 if (system("doas -u _nsd nsd-control reload")) {
94 return 0;
95 } else {
96 return 1;
97 }
98 }
100 # create A and AAAA records for subdomain, set the rDNS,
101 # and return the new ipv6 address
102 sub nextdns {
103 my ($subdomain) = @_;
104 my $ipv4 = shift(@ipv4s);
105 my $ipv6;
106 my $fqdn = "$subdomain.$hostname";
107 if ($ipv4 =~ /^[0-9]+\.[0-9]+\.[0-9]+\.([0-9]+)$/) {
108 $ipv6 = "2602:fccf:1:1".sprintf("%03d",$1)."::";
110 writefile($ipv4path, join("\n", @ipv4s));
111 my $success = setdns($fqdn, $ipv4) && setdns($fqdn, $ipv6) && setdns("ns1.$fqdn", $ipv4) && setdns("ns2.$fqdn", $ipv4);
112 return $success;
115 sub createshell {
116 my ($username, $password) = @_;
117 print "Username: $username\n";
118 print "Password: $password\n";
119 system "doas groupadd $username";
120 system "doas adduser -batch $username $username $username `encrypt $password`";
121 system "doas usermod -G vmdusers $username";
122 system "doas chmod -R o-rwx /home/$username";
123 system "doas su -l $username -c \"vmctl create -s 20G $username.qcow2\"";
124 print "VM created for $username!\n";
125 my @vmconf = readarray($vmconf);
126 my $lladdr;
127 foreach my $line (@vmconf) {
128 if ($line =~ /lladdr (.*)/) {
129 $lladdr = $1;
132 if (defined($lladdr) && $lladdr =~ /([0-9a-fA-F]{2})$/) {
133 $lladdr = $`.($1+1);
135 my $block = <<"EOF";
136 vm "$username" {
137 owner $username
138 memory 1024M
139 cdrom "/home/iso/install70.iso"
140 disk /home/$username/$username.qcow2
141 interface {
142 locked lladdr $lladdr
143 switch "switch0"
146 EOF
147 appendfile($vmconf, $block);
148 `doas vmctl reload`;
151 my $nargs = $#ARGV + 1;
152 if ($nargs != 1) {
153 print "\nUsage: install.pl username\n";
154 exit;
156 my $username = $ARGV[0];
157 my $password = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..12;
159 createshell($username, $password);
160 nextdns($username);