| 1 | #!/usr/bin/perl -w |
| 2 | # Copyright (C) 2000 by Sam Hartman |
| 3 | # This file may be copied either under the terms of the GNU GPL or the IBM |
| 4 | # Public License either version 2 or later of the GPL or version 1.0 or later |
| 5 | # of the IPL. |
| 6 | |
| 7 | use Term::ReadLine; |
| 8 | use strict; |
| 9 | use Debian::OpenAFS::ConfigUtils; |
| 10 | use Getopt::Long; |
| 11 | use Socket qw(inet_ntoa); |
| 12 | use vars qw($admin $server $requirements_met $shutdown_needed); |
| 13 | my $rl = new Term::ReadLine('afs-newcell'); |
| 14 | |
| 15 | # The default file server options are poor. Until they've been updated, use |
| 16 | # the following from Harald Barth; it should be an improvement for most |
| 17 | # people. |
| 18 | my $fs_options = '-p 23 -busyat 600 -rxpck 400 -s 1200 -l 1200 -cb 65535' |
| 19 | . ' -b 240 -vc 1200'; |
| 20 | |
| 21 | =head1 NAME |
| 22 | |
| 23 | afs-newcell - Set up initial database server for AFS cell |
| 24 | |
| 25 | =head1 SYNOPSIS |
| 26 | |
| 27 | B<afs-newcell> [B<--requirements-met>] [B<--admin> admin_user] |
| 28 | |
| 29 | =head1 DESCRIPTION |
| 30 | |
| 31 | This script sets up the initial AFS database and configures the first |
| 32 | database/file server. |
| 33 | |
| 34 | The B<--requirements-met> option specifies that the initial requirements have |
| 35 | been met and that the script can proceed without displaying the initial |
| 36 | banner or asking for confirmation. |
| 37 | |
| 38 | The B<--admin> option specifies the name of the administrative user. This |
| 39 | user will be given system:administrators and susers permission in the cell. |
| 40 | |
| 41 | =head1 AUTHOR |
| 42 | |
| 43 | Sam Hartman <hartmans@debian.org> |
| 44 | |
| 45 | =cut |
| 46 | |
| 47 | # Flush all output immediately. |
| 48 | $| = 1; |
| 49 | |
| 50 | GetOptions ("requirements-met" => \$requirements_met, "admin=s" => \$admin); |
| 51 | |
| 52 | unless ($requirements_met) { |
| 53 | print <<eoreqs; |
| 54 | Prerequisites |
| 55 | |
| 56 | In order to set up a new AFS cell, you must meet the following: |
| 57 | |
| 58 | 1) You need a working Kerberos realm with Kerberos4 support. You |
| 59 | should install Heimdal with KTH Kerberos compatibility or MIT |
| 60 | Kerberos 5. |
| 61 | |
| 62 | 2) You need to create the single-DES AFS key and load it into |
| 63 | /etc/openafs/server/KeyFile. If your cell's name is the same as |
| 64 | your Kerberos realm then create a principal called afs. Otherwise, |
| 65 | create a principal called afs/cellname in your realm. The cell |
| 66 | name should be all lower case, unlike Kerberos realms which are all |
| 67 | upper case. You can use asetkey from the openafs-krb5 package, or |
| 68 | if you used AFS3 salt to create the key, the bos addkey command. |
| 69 | |
| 70 | 3) This machine should have a filesystem mounted on /vicepa. If you |
| 71 | do not have a free partition, then create a large file by using dd |
| 72 | to extract bytes from /dev/zero. Create a filesystem on this file |
| 73 | and mount it using -oloop. |
| 74 | |
| 75 | 4) You will need an administrative principal created in a Kerberos |
| 76 | realm. This principal will be added to susers and |
| 77 | system:administrators and thus will be able to run administrative |
| 78 | commands. Generally the user is a root or admin instance of some |
| 79 | administrative user. For example if jruser is an administrator then |
| 80 | it would be reasonable to create jruser/admin (or jruser/root) and |
| 81 | specify that as the user to be added in this script. |
| 82 | |
| 83 | 5) The AFS client must not be running on this workstation. It will be |
| 84 | at the end of this script. |
| 85 | |
| 86 | eoreqs |
| 87 | #'# cperl-mode |
| 88 | |
| 89 | $_ = $rl->readline("Do you meet these requirements? [y/n] "); |
| 90 | unless (/^y/i ) { |
| 91 | print "Run this script again when you meet the requirements\n"; |
| 92 | exit(1); |
| 93 | } |
| 94 | |
| 95 | if ($> != 0) { |
| 96 | die "This script should almost always be run as root. Use the\n" |
| 97 | . "--requirements-met option to run as non-root.\n"; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | # Make sure the AFS client is not already running. |
| 102 | open(MOUNT, "mount |") or die "Failed to run mount: $!\n"; |
| 103 | while(<MOUNT>) { |
| 104 | if (m:^AFS:) { |
| 105 | print "The AFS client is currently running on this workstation.\n"; |
| 106 | print "Please restart this script after running" |
| 107 | . " service openafs-client stop\n"; |
| 108 | exit(1); |
| 109 | } |
| 110 | } |
| 111 | close MOUNT; |
| 112 | |
| 113 | # Make sure there is a keyfile. |
| 114 | unless ( -f "/etc/openafs/server/KeyFile") { |
| 115 | print "You do not have an AFS keyfile. Please create this using\n"; |
| 116 | print "asetkey from openafs-krb5 or the bos addkey command\n"; |
| 117 | exit(1); |
| 118 | } |
| 119 | |
| 120 | # Stop the file server. |
| 121 | print "If the fileserver is not running, this may hang for 30 seconds.\n"; |
| 122 | run("service openafs-fileserver stop"); |
| 123 | |
| 124 | # Get the local hostname. Use the fully-qualified hostname to be safer. |
| 125 | $server = `hostname -f`; |
| 126 | chomp $server; |
| 127 | my $ip = gethostbyname $server; |
| 128 | if (inet_ntoa($ip) eq '127.0.0.1') { |
| 129 | print "\n"; |
| 130 | print "Your hostname $server resolves to 127.0.0.1, which AFS cannot\n"; |
| 131 | print "cope with. Make sure your hostname resolves to a non-loopback\n"; |
| 132 | print "IP address. (Check /etc/hosts and make sure that your hostname\n"; |
| 133 | print "isn't listed on the 127.0.0.1 line. If it is, removing it from\n"; |
| 134 | print "that line will probably solve this problem.)\n"; |
| 135 | exit(1); |
| 136 | } |
| 137 | |
| 138 | # Determine the admin principal. |
| 139 | $admin = $rl->readline("What administrative principal should be used? ") |
| 140 | unless $admin; |
| 141 | print "\n"; |
| 142 | die "Please specify an administrative user\n" unless $admin; |
| 143 | my $afs_admin = $admin; |
| 144 | $afs_admin =~ s:/:.:g; |
| 145 | if ($afs_admin =~ /@/) { |
| 146 | die "The administrative user must be in the same realm as the cell and\n" |
| 147 | . "no realm may be specified.\n"; |
| 148 | } |
| 149 | |
| 150 | # Determine the local cell. This should be configured via debconf, from the |
| 151 | # openafs-client configuration, when openafs-fileserver is installed. |
| 152 | open(CELL, "/etc/openafs/server/ThisCell") |
| 153 | or die "Cannot open /etc/openafs/server/ThisCell: $!\n"; |
| 154 | my $cell = <CELL>; |
| 155 | chomp $cell; |
| 156 | |
| 157 | # Make sure the new cell is configured in the client CellServDB. |
| 158 | open(CELLSERVDB, "/etc/openafs/CellServDB") |
| 159 | or die "Cannot open /etc/openafs/CellServDB: $!\n"; |
| 160 | my $found = 0; |
| 161 | while (<CELLSERVDB>) { |
| 162 | next unless /^>\Q$cell\E\s/; |
| 163 | while (<CELLSERVDB>) { |
| 164 | last if /^>/; |
| 165 | my ($dbserver) = split ' '; |
| 166 | if ($dbserver eq inet_ntoa($ip)) { |
| 167 | $found = 1; |
| 168 | last; |
| 169 | } |
| 170 | } |
| 171 | last; |
| 172 | } |
| 173 | unless ($found) { |
| 174 | print "\n"; |
| 175 | print "The new cell $cell is not configured in /etc/openafs/CellServDB\n"; |
| 176 | print "Add configuration like:\n\n"; |
| 177 | print ">$cell\n"; |
| 178 | print inet_ntoa($ip), "\t\t\t#$server\n\n"; |
| 179 | print "to that file before continuing.\n"; |
| 180 | exit(1); |
| 181 | } |
| 182 | |
| 183 | # Write out a new CellServDB for the local cell containing only this server. |
| 184 | if (-f "/etc/openafs/server/CellServDB") { |
| 185 | print "/etc/openafs/server/CellServDB already exists, renaming to .old\n"; |
| 186 | rename("/etc/openafs/server/CellServDB", |
| 187 | "/etc/openafs/server/CellServDB.old") |
| 188 | or die "Cannot rename /etc/openafs/server/CellServDB: $!\n"; |
| 189 | } |
| 190 | open(CELLSERVDB, "> /etc/openafs/server/CellServDB") |
| 191 | or die "Cannot create /etc/openafs/server/CellServDB: $!\n"; |
| 192 | print CELLSERVDB ">$cell\n"; |
| 193 | print CELLSERVDB inet_ntoa($ip), "\t\t\t#$server\n"; |
| 194 | close CELLSERVDB or die "Cannot write to /etc/openafs/server/CellServDB: $!\n"; |
| 195 | |
| 196 | # Now, we should be able to start bos and add the admin user. |
| 197 | run("service openafs-fileserver start"); |
| 198 | $shutdown_needed = 1; |
| 199 | run("bos adduser $server $afs_admin -localauth"); |
| 200 | unwind("bos removeuser $server $afs_admin -localauth"); |
| 201 | |
| 202 | # Create the initial protection database using pt_util. This is safer than |
| 203 | # the standard mechanism of starting the cell in noauth mode until the first |
| 204 | # user has been created. |
| 205 | if (-f "/var/lib/openafs/db/prdb.DB0") { |
| 206 | warn "ERROR: Protection database already exists; cell already partially\n"; |
| 207 | warn "ERROR: created. If you do not want the current database, remove\n"; |
| 208 | warn "ERROR: all files in /var/lib/openafs/db and then run this program\n"; |
| 209 | warn "ERROR: again.\n"; |
| 210 | exit(1); |
| 211 | } |
| 212 | print "\nCreating initial protection database. This will print some errors\n"; |
| 213 | print "about an id already existing and a bad ubik magic. These errors can\n"; |
| 214 | print "be safely ignored.\n\n"; |
| 215 | open(PRDB, "| pt_util -p /var/lib/openafs/db/prdb.DB0 -w") |
| 216 | or die "Unable to start pt_util: $!\n"; |
| 217 | print PRDB "$afs_admin 128/20 1 -204 -204\n"; |
| 218 | print PRDB "system:administrators 130/20 -204 -204 -204\n"; |
| 219 | print PRDB " $afs_admin 1\n"; |
| 220 | close PRDB; |
| 221 | unwind("rm /var/lib/openafs/db/prdb*"); |
| 222 | print "\n"; |
| 223 | |
| 224 | # We should now be able to start ptserver and vlserver. |
| 225 | run("bos create $server ptserver simple /usr/lib/openafs/ptserver -localauth"); |
| 226 | unwind("bos delete $server ptserver -localauth"); |
| 227 | run("bos create $server vlserver simple /usr/lib/openafs/vlserver -localauth"); |
| 228 | unwind("bos delete $server vlserver -localauth"); |
| 229 | |
| 230 | # Create a file server as well. |
| 231 | run("bos create $server dafs dafs" |
| 232 | . " -cmd '/usr/lib/openafs/dafileserver $fs_options'" |
| 233 | . " -cmd /usr/lib/openafs/davolserver" |
| 234 | . " -cmd /usr/lib/openafs/salvageserver" |
| 235 | . " -cmd /usr/lib/openafs/dasalvager -localauth"); |
| 236 | unwind("bos delete $server dafs -localauth"); |
| 237 | |
| 238 | # Make sure that there is no scheduled general restart time; it's not needed. |
| 239 | run("bos setrestart $server -time never -general -localauth"); |
| 240 | |
| 241 | # Pause for a while for ubik to catch up. |
| 242 | print "Waiting for database elections: "; |
| 243 | sleep(30); |
| 244 | print "done.\n"; |
| 245 | |
| 246 | # Past this point we want to control when bos shutdown happens. |
| 247 | $shutdown_needed = 0; |
| 248 | unwind("bos shutdown $server -localauth -wait"); |
| 249 | run("vos create $server a root.afs -localauth"); |
| 250 | unwind("vos remove $server a root.afs -localauth"); |
| 251 | |
| 252 | # We should now be able to bring up the client (it may need root.afs to exist |
| 253 | # if not using dynroot). We override whatever default cell was configured for |
| 254 | # the client, just in case it was pointing to some other cell. |
| 255 | open(THIS, "> /etc/openafs/ThisCell") |
| 256 | or die "ERROR: Cannot create /etc/openafs/ThisCell: $!\n"; |
| 257 | print THIS "$cell\n"; |
| 258 | close THIS or die "ERROR: Cannot write to /etc/openafs/ThisCell: $!\n"; |
| 259 | run("service openafs-client force-start"); |
| 260 | |
| 261 | # Verify that AFS has managed to start. |
| 262 | my $afs_running = 0; |
| 263 | open(MOUNT, "mount |") or die "ERROR: Failed to run mount: $!\n"; |
| 264 | while(<MOUNT>) { |
| 265 | if (m:^AFS:) { |
| 266 | $afs_running = 1; |
| 267 | } |
| 268 | } |
| 269 | unless ($afs_running) { |
| 270 | print "ERROR: The AFS client failed to start.\n"; |
| 271 | print "ERROR: Please fix whatever problem kept it from running.\n"; |
| 272 | exit(1); |
| 273 | } |
| 274 | print "\n"; |
| 275 | print "Now, get tokens as $admin in the $cell cell.\n"; |
| 276 | print "Then, run afs-rootvol.\n"; |
| 277 | |
| 278 | # Success, so clear the unwind commands. |
| 279 | @unwinds = (); |
| 280 | |
| 281 | # If we fail before all the instances are created, we need to back out of |
| 282 | # everything we did as much as possible. |
| 283 | END { |
| 284 | if ($shutdown_needed || @unwinds) { |
| 285 | print "\nCell setup failed, ABORTING\n"; |
| 286 | } |
| 287 | system("bos shutdown $server -localauth -wait") if $shutdown_needed; |
| 288 | run(pop @unwinds) while @unwinds; |
| 289 | } |