Annotation of loncom/manage_ssl_certs.pl, revision 1.1
1.1 ! raeburn 1: #!/usr/bin/perl
! 2: $|=1;
! 3: # Displays status of LON-CAPA SSL certs, and allows new certificate
! 4: # signing requests to be created and e-mailed to CA for cluster to
! 5: # which server/VM belongs.
! 6: # $Id: manage_ssl_certs.pl,v 1.1 2018/08/18 19:00:00 raeburn Exp $
! 7: #
! 8: # Copyright Michigan State University Board of Trustees
! 9: #
! 10: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
! 11: #
! 12: # LON-CAPA is free software; you can redistribute it and/or modify
! 13: # it under the terms of the GNU General Public License as published by
! 14: # the Free Software Foundation; either version 2 of the License, or
! 15: # (at your option) any later version.
! 16: #
! 17: # LON-CAPA is distributed in the hope that it will be useful,
! 18: # but WITHOUT ANY WARRANTY; without even the implied warranty of
! 19: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 20: # GNU General Public License for more details.
! 21: #
! 22: # You should have received a copy of the GNU General Public License
! 23: # along with LON-CAPA; if not, write to the Free Software
! 24: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
! 25: #
! 26: # /home/httpd/html/adm/gpl.txt
! 27: #
! 28: # http://www.lon-capa.org/
! 29: #
! 30:
! 31: use strict;
! 32: use lib '/home/httpd/lib/perl/';
! 33: use LONCAPA::Configuration;
! 34: use LONCAPA::Lond;
! 35: use LONCAPA::SSL;
! 36: use LONCAPA;
! 37: use Term::ReadKey;
! 38: use Locale::Country;
! 39:
! 40: my ($lonCluster,$domainDescription,$hostname,$certmail,
! 41: $certsdir,$privkey,$connectcsr,$replicatecsr);
! 42:
! 43: print(<<END);
! 44:
! 45: ===============================================================================
! 46:
! 47: Which type of LON-CAPA cluster does this server/VM belong to?
! 48: IMPORTANT: to take advantage of the cluster options 1) and 3),
! 49: you must have been or expect to be accepted into the cluster.
! 50: Contact loncapa\@loncapa.org for access.
! 51:
! 52: 1) PRODUCTION - you have (or will) connect this machine to the
! 53: LON-CAPA content sharing network. This setting is for
! 54: schools, colleges, and universities, that currently
! 55: are running - or in the future will run - courses.
! 56: 2) STAND-ALONE - you want this machine to run in 'stand-alone' mode and
! 57: not be connected to other LON-CAPA machines.
! 58: 3) DEVELOPMENT - you want to do software (not content!) development with
! 59: this workstation and eventually link it with
! 60: workstations of other LON-CAPA software developers.
! 61: 4) RUNNING YOUR OWN CLUSTER - this machine is not in the standard LON-CAPA
! 62: cluster and won't be in the future.
! 63: (This choice is unlikely what you want to select.)
! 64: END
! 65:
! 66: my $flag=0;
! 67: while (!$flag) {
! 68: print "ENTER 1, 2, 3, or 4:\n";
! 69: my $choice=<>;
! 70: chomp($choice);
! 71: if ($choice==1) {
! 72: $lonCluster='production'; $flag=1;
! 73: } elsif ($choice==2) {
! 74: $lonCluster='standalone'; $flag=1;
! 75: } elsif ($choice==3) {
! 76: $lonCluster='development'; $flag=1;
! 77: } elsif ($choice==4) {
! 78: $lonCluster='existing'; $flag=1;
! 79: my $earlyout;
! 80: foreach my $file ('hosts.tab','dns_hosts.tab',
! 81: 'domain.tab','dns_domain.tab') {
! 82: unless (-e '/home/httpd/lonTabs/'.$file) {
! 83: print <<END;
! 84: There is no existing /home/httpd/lonTabs/$file
! 85: END
! 86: $earlyout = 1;
! 87: }
! 88: }
! 89: if ($earlyout) {
! 90: exit;
! 91: }
! 92: }
! 93: }
! 94:
! 95: $flag = 0;
! 96: my $dist=`/home/httpd/perl/distprobe`;
! 97: my $confdir = '/etc/httpd/conf/';
! 98: if ($dist =~ /^(sles|suse|ubuntu|debian)/) {
! 99: $confdir = '/etc/apache2/';
! 100: }
! 101:
! 102: my $filename='loncapa.conf';
! 103: my %perlvar;
! 104: if (-e "$confdir$filename") {
! 105: if (open(CONFIG,'<',$confdir.$filename) or die("Can't read $confdir$filename")) {
! 106: while (my $configline=<CONFIG>) {
! 107: if ($configline =~ /^[^\#]*PerlSetVar/) {
! 108: my ($unused,$varname,$varvalue)=split(/\s+/,$configline);
! 109: chomp($varvalue);
! 110: $perlvar{$varname}=$varvalue if $varvalue!~/^\{\[\[\[\[/;
! 111: }
! 112: }
! 113: close(CONFIG);
! 114: }
! 115: }
! 116:
! 117: my $perlstaticref = &get_static_config($confdir);
! 118: if (ref($perlstaticref) ne 'HASH') {
! 119: exit;
! 120: }
! 121:
! 122: if (open(IN,'<','/home/httpd/lonTabs/domain.tab')) {
! 123: while(my $line = <IN>) {
! 124: if ($line =~ /^\Q$perlvar{'lonDefDomain'}\E\:/) {
! 125: (undef,$domainDescription)=split(/:/,$line);
! 126: chomp($domainDescription);
! 127: last;
! 128: }
! 129: }
! 130: close(IN);
! 131: }
! 132:
! 133: if (open(IN,'<','/home/httpd/lonTabs/hosts.tab')) {
! 134: while(my $line = <IN>) {
! 135: if ($line =~ /^\Q$perlvar{'lonHostID'}\E\:/) {
! 136: (undef,undef,undef,$hostname)=split(/:/,$line);
! 137: last;
! 138: }
! 139: }
! 140: close(IN);
! 141: }
! 142:
! 143: $certsdir = $perlstaticref->{'lonCertificateDirectory'};
! 144: $privkey = $perlstaticref->{'lonnetPrivateKey'};
! 145: $connectcsr = $perlstaticref->{'lonnetCertificate'};
! 146: $connectcsr =~ s/\.pem$/.csr/;
! 147: $replicatecsr = $perlstaticref->{'lonnetHostnameCertificate'};
! 148: $replicatecsr =~ s/\.pem$/.csr/;
! 149:
! 150:
! 151: $certmail = &get_mail();
! 152:
! 153: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 154: my ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 155: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 156: print $certinfo;
! 157: my %sslstatus;
! 158: if (ref($sslref) eq 'HASH') {
! 159: %sslstatus = %{$sslref};
! 160: }
! 161: while (!$flag) {
! 162: print(<<END);
! 163:
! 164: ===============================================================================
! 165:
! 166: This is now the current configuration of your machine.
! 167: 1) Private Key for SSL: $lonkeystatus
! 168: 2) SSL Certificate for LON-CAPA server connections: $lonhostcertstatus
! 169: 3) SSL Certificate for Content Replication: $lonhostnamecertstatus
! 170: 4) Everything is correct up above
! 171:
! 172: ENTER A CHOICE OF 1 TO 3 TO CHANGE, OTHERWISE ENTER 4:
! 173: END
! 174:
! 175: my $choice=<>;
! 176: chomp($choice);
! 177: if ($choice==1) {
! 178: if ($sslstatus{'key'} == 1) {
! 179: print(<<END);
! 180: 1) Private Key for SSL: $lonkeystatus
! 181:
! 182: POSSIBLE CHOICES:
! 183: 1) overwrite existing key
! 184: 2) make no change
! 185: ENTER NEW VALUE
! 186: END
! 187: my $choice2=<>;
! 188: chomp($choice2);
! 189: if ($choice2 eq '1') {
! 190: my $sslkeypass = &get_new_sslkeypass();
! 191: &make_key($certsdir,$privkey,$sslkeypass);
! 192: }
! 193: } elsif ($sslstatus{'key'} == 0) {
! 194: print(<<END);
! 195: 1) Private Key for SSL: $lonkeystatus
! 196: END
! 197: my $sslkeypass = &get_new_sslkeypass();
! 198: &make_key($certsdir,$privkey,$sslkeypass);
! 199: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 200: ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 201: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 202: if (ref($sslref) eq 'HASH') {
! 203: %sslstatus = %{$sslref};
! 204: }
! 205: }
! 206: } elsif ($choice==2) {
! 207: if (($sslstatus{'host'} == 1) || ($sslstatus{'host'} == 2) || ($sslstatus{'host'} == 3)) {
! 208: print(<<END);
! 209: 2) SSL Certificate for LON-CAPA server connections: $lonhostcertstatus
! 210:
! 211: POSSIBLE CHOICES:
! 212: 1) create new certificate signing request with new key
! 213: 2) create new certificate signing request with existing key
! 214: 3) resend current certificate signing request
! 215: 4) make no change
! 216: ENTER NEW VALUE
! 217: END
! 218:
! 219: my $choice2=<>;
! 220: chomp($choice2);
! 221: if (($choice2 eq '1') || ($choice2 eq '2')) {
! 222: &ssl_info();
! 223: my $country = &get_country($hostname);
! 224: my $state = &get_state();
! 225: my $city = &get_city();
! 226: my $connectsubj = "/C=$country/ST=$state/O=$domainDescription/L=$city/CN=$perlvar{'lonHostID'}/OU=LONCAPA/emailAddress=$certmail";
! 227: ($domainDescription,$country,$state,$city) = &confirm_locality($domainDescription,$country,$state,$city);
! 228: my $sslkeypass;
! 229: if ($choice2 eq '1') {
! 230: $sslkeypass = &get_new_sslkeypass();
! 231: &make_key($certsdir,$privkey,$sslkeypass);
! 232: } elsif ($choice2 eq '2') {
! 233: $sslkeypass = &get_password('Enter existing password for SSL key');
! 234: &encrypt_key($certsdir,$privkey,$sslkeypass);
! 235: }
! 236: &make_host_csr($certsdir,$sslkeypass,$connectcsr,$connectsubj);
! 237: &mail_csr('host',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 238: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 239: ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 240: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 241: if (ref($sslref) eq 'HASH') {
! 242: %sslstatus = %{$sslref};
! 243: }
! 244: } elsif ($choice2 eq '3') {
! 245: if (-e "$certsdir/$connectcsr") {
! 246: &mail_csr('host',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 247: }
! 248: }
! 249: } elsif (($sslstatus{'host'} == 0) || ($sslstatus{'host'} == 4) || ($sslstatus{'host'} == 5)) {
! 250: my $sslkeypass;
! 251: if ($sslstatus{'key'} == 1) {
! 252: print(<<END);
! 253: 2) SSL Certificate for LON-CAPA server connections: $lonhostcertstatus
! 254:
! 255: POSSIBLE CHOICES:
! 256: 1) create new certificate signing request with new key
! 257: 2) create new certificate signing request with existing key
! 258: 3) make no change
! 259: ENTER NEW VALUE
! 260: END
! 261: my $choice2=<>;
! 262: chomp($choice2);
! 263: if ($choice2 eq '1') {
! 264: $sslkeypass = &get_new_sslkeypass();
! 265: &make_key($certsdir,$privkey,$sslkeypass);
! 266: } elsif ($choice2 eq '2') {
! 267: $sslkeypass = &get_password('Enter existing password for SSL key');
! 268: &encrypt_key($certsdir,$privkey,$sslkeypass);
! 269: }
! 270: } else {
! 271: print(<<END);
! 272: 2) SSL Certificate for LON-CAPA server connections: $lonhostcertstatus
! 273: END
! 274: $sslkeypass = &get_new_sslkeypass();
! 275: }
! 276: &ssl_info();
! 277: my $country = &get_country($hostname);
! 278: my $state = &get_state();
! 279: my $city = &get_city();
! 280: my $connectsubj = "/C=$country/ST=$state/O=$domainDescription/L=$city/CN=$perlvar{'lonHostID'}/OU=LONCAPA/emailAddress=$certmail";
! 281: &make_host_csr($certsdir,$sslkeypass,$connectcsr,$connectsubj);
! 282: &mail_csr('host',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 283: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 284: ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 285: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 286: if (ref($sslref) eq 'HASH') {
! 287: %sslstatus = %{$sslref};
! 288: }
! 289: }
! 290: } elsif ($choice==3) {
! 291: if (($sslstatus{'hostname'} == 1) || ($sslstatus{'hostname'} == 2) || ($sslstatus{'hostname'} == 3)) {
! 292: print(<<END);
! 293: 3) SSL Certificate for Content Replication: $lonhostnamecertstatus
! 294:
! 295: POSSIBLE CHOICES:
! 296: 1) create new certificate signing request with new key
! 297: 2) create new certificate signing request with existing key
! 298: 3) resend current certificate signing request
! 299: 4) make no change
! 300: ENTER NEW VALUE
! 301: END
! 302: my $choice2=<>;
! 303: chomp($choice2);
! 304: if (($choice2 eq '1') || ($choice2 eq '2')) {
! 305: &ssl_info();
! 306: my $country = &get_country($hostname);
! 307: my $state = &get_state();
! 308: my $city = &get_city();
! 309: my $replicatesubj = "/C=$country/ST=$state/O=$domainDescription/L=$city/CN=internal-$hostname/OU=LONCAPA/emailAddress=$certmail";
! 310: my $sslkeypass;
! 311: if ($choice2 eq '1') {
! 312: $sslkeypass = &get_new_sslkeypass();
! 313: &make_key($certsdir,$privkey,$sslkeypass);
! 314: } elsif ($choice2 eq '2') {
! 315: $sslkeypass = &get_password('Enter existing password for SSL key');
! 316: &encrypt_key($certsdir,$privkey,$sslkeypass);
! 317: }
! 318: &make_hostname_csr($certsdir,$sslkeypass,$replicatecsr,$replicatesubj);
! 319: &mail_csr('hostname',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 320: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 321: ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 322: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 323: if (ref($sslref) eq 'HASH') {
! 324: %sslstatus = %{$sslref};
! 325: }
! 326: } elsif ($choice2 eq '3') {
! 327: if (-e "$certsdir/$replicatecsr") {
! 328: &mail_csr('hostname',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 329: }
! 330: }
! 331: } elsif (($sslstatus{'hostname'} == 0) || ($sslstatus{'hostname'} == 4) || ($sslstatus{'hostname'} == 5)) {
! 332: my $sslkeypass;
! 333: if ($sslstatus{'key'} == 1) {
! 334: print(<<END);
! 335: 3) SSL Certificate for Content Replication: $lonhostnamecertstatus
! 336:
! 337: POSSIBLE CHOICES:
! 338: 1) create new certificate signing request with new key
! 339: 2) create new certificate signing request with existing key
! 340: 3) make no change
! 341: ENTER NEW VALUE
! 342: END
! 343: my $choice2=<>;
! 344: chomp($choice2);
! 345: if ($choice2 eq '1') {
! 346: $sslkeypass = &get_new_sslkeypass();
! 347: &make_key($certsdir,$privkey,$sslkeypass);
! 348: } elsif ($choice2 eq '2') {
! 349: $sslkeypass = &get_password('Enter existing password for SSL key');
! 350: &encrypt_key($certsdir,$privkey,$sslkeypass);
! 351: }
! 352: } else {
! 353: print(<<END);
! 354: 3) SSL Certificate for Content Replication: $lonhostnamecertstatus
! 355: END
! 356: $sslkeypass = &get_new_sslkeypass();
! 357: }
! 358: &ssl_info();
! 359: my $country = &get_country($hostname);
! 360: my $state = &get_state();
! 361: my $city = &get_city();
! 362: my $replicatesubj = "/C=$country/ST=$state/O=$domainDescription/L=$city/CN=internal-$hostname/OU=LONCAPA/emailAddress=$certmail";
! 363: &make_hostname_csr($certsdir,$sslkeypass,$replicatecsr,$replicatesubj);
! 364: &mail_csr('hostname',$lonCluster,$perlvar{'lonHostID'},$hostname,$certsdir,$connectcsr,$replicatecsr,$perlstaticref);
! 365: print "\nRetrieving status information for SSL key and certificates ...\n\n";
! 366: ($certinfo,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,$sslref) =
! 367: &get_cert_status($perlvar{'lonHostID'},$hostname,$perlstaticref);
! 368: if (ref($sslref) eq 'HASH') {
! 369: %sslstatus = %{$sslref};
! 370: }
! 371: }
! 372: } elsif ($choice==4) {
! 373: $flag=1;
! 374: } else {
! 375: print "Invalid input.\n";
! 376: }
! 377: }
! 378:
! 379: exit;
! 380:
! 381: sub get_static_config {
! 382: my ($confdir) = @_;
! 383: my $filename='loncapa_apache.conf';
! 384: my %LCperlvar;
! 385: if (-e "$confdir$filename") {
! 386: open(CONFIG,'<',$confdir.$filename) or die("Can't read $confdir$filename");
! 387: while (my $configline=<CONFIG>) {
! 388: if ($configline =~ /^[^\#]?PerlSetVar/) {
! 389: my ($unused,$varname,$varvalue)=split(/\s+/,$configline);
! 390: chomp($varvalue);
! 391: $LCperlvar{$varname}=$varvalue;
! 392: }
! 393: }
! 394: close(CONFIG);
! 395: }
! 396: return \%LCperlvar;
! 397: }
! 398:
! 399: sub get_sslnames {
! 400: my %sslnames = (
! 401: key => 'lonnetPrivateKey',
! 402: host => 'lonnetCertificate',
! 403: hostname => 'lonnetHostnameCertificate',
! 404: ca => 'lonnetCertificateAuthority',
! 405: );
! 406: return %sslnames;
! 407: }
! 408:
! 409: sub get_ssldesc {
! 410: my %ssldesc = (
! 411: key => 'Private Key',
! 412: host => 'Connections Certificate',
! 413: hostname => 'Replication Certificate',
! 414: ca => 'LON-CAPA CA Certificate',
! 415: );
! 416: return %ssldesc;
! 417: }
! 418:
! 419: sub get_cert_status {
! 420: my ($lonHostID,$hostname,$perlvarstatic) = @_;
! 421: my $currcerts = &LONCAPA::SSL::print_certstatus({$lonHostID => $hostname,},'text','cgi');
! 422: my ($lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,%sslstatus);
! 423: my $output = '';
! 424: if ($currcerts eq "$lonHostID:error") {
! 425: $output .= "No information available for SSL certificates\n";
! 426: $sslstatus{'key'} = -1;
! 427: $sslstatus{'host'} = -1;
! 428: $sslstatus{'hostname'} = -1;
! 429: $sslstatus{'ca'} = -1;
! 430: $lonkeystatus = 'unknown status';
! 431: $lonhostcertstatus = 'unknown status';
! 432: $lonhostnamecertstatus = 'unknown status';
! 433: } else {
! 434: my %sslnames = &get_sslnames();
! 435: my %ssldesc = &get_ssldesc();
! 436: my %csr;
! 437: my ($lonhost,$info) = split(/\:/,$currcerts,2);
! 438: if ($lonhost eq $lonHostID) {
! 439: my @items = split(/\&/,$info);
! 440: foreach my $item (@items) {
! 441: my ($key,$value) = split(/=/,$item,2);
! 442: if ($key =~ /^(host(?:|name))\-csr$/) {
! 443: $csr{$1} = $value;
! 444: }
! 445: my @data = split(/,/,$value);
! 446: if (grep(/^\Q$key\E$/,keys(%sslnames))) {
! 447: my ($checkcsr,$comparecsr);
! 448: if (lc($data[0]) eq 'yes') {
! 449: $output .= "$ssldesc{$key} ".$perlvarstatic->{$sslnames{$key}}." available with status = $data[1]\n";
! 450: if ($key eq 'key') {
! 451: $lonkeystatus = "status: $data[1]";
! 452: if ($data[1] =~ /ok$/) {
! 453: $sslstatus{$key} = 1;
! 454: }
! 455: } else {
! 456: my $setstatus;
! 457: if (($key eq 'host') || ($key eq 'hostname')) {
! 458: if ($data[1] eq 'otherkey') {
! 459: $sslstatus{$key} = 4;
! 460: $setstatus = 1;
! 461: if ($key eq 'host') {
! 462: $lonhostcertstatus = "status: created with different key";
! 463: } elsif ($key eq 'hostname') {
! 464: $lonhostnamecertstatus = "status: created with different key";
! 465: }
! 466: } elsif ($data[1] eq 'nokey') {
! 467: $sslstatus{$key} = 5;
! 468: $setstatus = 1;
! 469: if ($key eq 'host') {
! 470: $lonhostcertstatus = "status: created with missing key";
! 471: } elsif ($key eq 'hostname') {
! 472: $lonhostnamecertstatus = "status: created with missing key";
! 473: }
! 474: }
! 475: if ($setstatus) {
! 476: $comparecsr = 1;
! 477: }
! 478: }
! 479: unless ($setstatus) {
! 480: if ($data[1] eq 'expired') {
! 481: $sslstatus{$key} = 2;
! 482: if (($key eq 'host') || ($key eq 'hostname')) {
! 483: $comparecsr = 1;
! 484: }
! 485: } elsif ($data[1] eq 'future') {
! 486: $sslstatus{$key} = 3;
! 487: $sslstatus{$key} = 3;
! 488: } else {
! 489: $sslstatus{$key} = 1;
! 490: }
! 491: if ($key eq 'host') {
! 492: $lonhostcertstatus = "status: $data[1]";
! 493: } elsif ($key eq 'hostname') {
! 494: $lonhostnamecertstatus = "status: $data[1]";
! 495: }
! 496: }
! 497: }
! 498: } else {
! 499: $sslstatus{$key} = 0;
! 500: $output .= "$ssldesc{$key} ".$perlvarstatic->{$sslnames{$key}}." not available\n";
! 501: if ($key eq 'key') {
! 502: $lonkeystatus = 'still needed';
! 503: } elsif (($key eq 'host') || ($key eq 'hostname')) {
! 504: $checkcsr = 1;
! 505: }
! 506: }
! 507: if (($checkcsr) || ($comparecsr)) {
! 508: my $csrfile = $perlvarstatic->{$sslnames{$key}};
! 509: $csrfile =~s /\.pem$/.csr/;
! 510: my $csrstatus;
! 511: if (-e $perlvarstatic->{'lonCertificateDirectory'}."/$csrfile") {
! 512: if (open(PIPE,"openssl req -text -noout -verify -in ".$perlvarstatic->{'lonCertificateDirectory'}."/$csrfile 2>&1 |")) {
! 513: while(<PIPE>) {
! 514: chomp();
! 515: $csrstatus = $_;
! 516: last;
! 517: }
! 518: close(PIPE);
! 519: if ($comparecsr) {
! 520: my $csrhash;
! 521: if (open(PIPE,"openssl x509 -in certificate.crt -pubkey -noout -outform pem | sha256sum")) {
! 522: $csrhash = <PIPE>;
! 523: close(PIPE);
! 524: }
! 525: }
! 526: }
! 527: $output .= "Certificate signing request for $ssldesc{$key} available with status = $csrstatus\n\n";
! 528: if ($key eq 'host') {
! 529: $lonhostcertstatus = 'awaiting signature';
! 530: } else {
! 531: $lonhostnamecertstatus = 'awaiting signature';
! 532: }
! 533: $sslstatus{$key} = 3;
! 534: } elsif ($checkcsr) {
! 535: $output .= "No certificate signing request available for $ssldesc{$key}\n\n";
! 536: if ($key eq 'host') {
! 537: $lonhostcertstatus = 'still needed';
! 538: } else {
! 539: $lonhostnamecertstatus = 'still needed';
! 540: }
! 541: }
! 542: }
! 543: }
! 544: }
! 545: # FIXME If different key, or missing key, or expired, check if there is a csr that does not match the cert, and that may be awaiting signature.
! 546: }
! 547: }
! 548: return ($output,$lonkeystatus,$lonhostcertstatus,$lonhostnamecertstatus,\%sslstatus);
! 549: }
! 550:
! 551: sub get_new_sslkeypass {
! 552: my $sslkeypass;
! 553: my $flag=0;
! 554: # get Password for SSL key
! 555: while (!$flag) {
! 556: $sslkeypass = &make_passphrase();
! 557: if ($sslkeypass) {
! 558: $flag = 1;
! 559: } else {
! 560: print "Invalid input (a password is required for the SSL key).\n";
! 561: }
! 562: }
! 563: return $sslkeypass;
! 564: }
! 565:
! 566: sub make_passphrase {
! 567: my ($got_passwd,$firstpass,$secondpass,$passwd);
! 568: my $maxtries = 10;
! 569: my $trial = 0;
! 570: while ((!$got_passwd) && ($trial < $maxtries)) {
! 571: $firstpass = &get_password('Enter a password for the SSL key (at least 6 characters long)');
! 572: if (length($firstpass) < 6) {
! 573: print('Password too short.'."\n".
! 574: 'Please choose a password with at least six characters.'."\n".
! 575: 'Please try again.'."\n");
! 576: } elsif (length($firstpass) > 30) {
! 577: print('Password too long.'."\n".
! 578: 'Please choose a password with no more than thirty characters.'."\n".
! 579: 'Please try again.'."\n");
! 580: } else {
! 581: my $pbad=0;
! 582: foreach (split(//,$firstpass)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
! 583: if ($pbad) {
! 584: print('Password contains invalid characters.'."\n".
! 585: 'Password must consist of standard ASCII characters.'."\n".
! 586: 'Please try again.'."\n");
! 587: } else {
! 588: $secondpass = &get_password('Enter password a second time');
! 589: if ($firstpass eq $secondpass) {
! 590: $got_passwd = 1;
! 591: $passwd = $firstpass;
! 592: } else {
! 593: print('Passwords did not match.'."\n".
! 594: 'Please try again.'."\n");
! 595: }
! 596: }
! 597: }
! 598: $trial ++;
! 599: }
! 600: return $passwd;
! 601: }
! 602:
! 603: sub get_password {
! 604: my ($prompt) = @_;
! 605: local $| = 1;
! 606: print $prompt.': ';
! 607: my $newpasswd = '';
! 608: ReadMode 'raw';
! 609: my $key;
! 610: while(ord($key = ReadKey(0)) != 10) {
! 611: if(ord($key) == 127 || ord($key) == 8) {
! 612: chop($newpasswd);
! 613: print "\b \b";
! 614: } elsif(!ord($key) < 32) {
! 615: $newpasswd .= $key;
! 616: print '*';
! 617: }
! 618: }
! 619: ReadMode 'normal';
! 620: print "\n";
! 621: return $newpasswd;
! 622: }
! 623:
! 624: sub send_mail {
! 625: my ($hostname,$recipient,$subj,$file) = @_;
! 626: my $from = 'www@'.$hostname;
! 627: my $certmail = "To: $recipient\n".
! 628: "From: $from\n".
! 629: "Subject: ".$subj."\n".
! 630: "Content-type: text/plain\; charset=UTF-8\n".
! 631: "MIME-Version: 1.0\n\n";
! 632: if (open(my $fh,"<$file")) {
! 633: while (<$fh>) {
! 634: $certmail .= $_;
! 635: }
! 636: close($fh);
! 637: $certmail .= "\n\n";
! 638: if (open(my $mailh, "|/usr/lib/sendmail -oi -t -odb")) {
! 639: print $mailh $certmail;
! 640: close($mailh);
! 641: print "Mail sent ($subj) to $recipient\n";
! 642: } else {
! 643: print "Sending mail ($subj) to $recipient failed.\n";
! 644: }
! 645: }
! 646: return;
! 647: }
! 648:
! 649: sub mail_csr {
! 650: my ($types,$lonCluster,$lonHostID,$hostname,$certsdir,$connectcsr,$replicatecsr,$perlvarref) = @_;
! 651: my ($camail,$flag);
! 652: if ($lonCluster eq 'production' || $lonCluster eq 'development') {
! 653: $camail = $perlvarref->{'SSLEmail'};
! 654: } else {
! 655: $flag=0;
! 656: # get Certificate Authority E-mail
! 657: while (!$flag) {
! 658: print(<<END);
! 659:
! 660: ENTER EMAIL ADDRESS TO SEND CERTIFICATE SIGNING REQUESTS
! 661: END
! 662:
! 663: my $choice=<>;
! 664: chomp($choice);
! 665: if ($choice ne '') {
! 666: open(OUT,'>>/tmp/loncapa_updatequery.out');
! 667: print(OUT 'Certificate Authority Email Address'."\t".$choice."\n");
! 668: close(OUT);
! 669: $camail=$choice;
! 670: $flag=1;
! 671: } else {
! 672: print "Invalid input (an email address is required).\n";
! 673: }
! 674: }
! 675: }
! 676: if ($camail) {
! 677: my $subj;
! 678: if (($types eq 'both') || ($types = 'host')) {
! 679: if (-e "$certsdir/$connectcsr") {
! 680: $subj = "Certificate Request ($lonHostID)";
! 681: print(&send_mail($hostname,$camail,$subj,"$certsdir/$connectcsr"));
! 682: }
! 683: }
! 684: if (($types eq 'both') || ($types = 'hostname')) {
! 685: if (-e "$certsdir/$replicatecsr") {
! 686: $subj = "Certificate Request (internal-$hostname)";
! 687: print(&send_mail($hostname,$camail,$subj,"$certsdir/$replicatecsr"));
! 688: }
! 689: }
! 690: }
! 691: }
! 692:
! 693: sub ssl_info {
! 694: print(<<END);
! 695:
! 696: ****** Information about Country, State or Province and City *****
! 697:
! 698: A two-letter country code, e.g., US, CA, DE etc. as defined by ISO 3166,
! 699: is required. A state or province, and a city are also required.
! 700: This locality information is included in two SSL certificates used internally
! 701: by LON-CAPA, unless you are running standalone.
! 702:
! 703: If your server will be part of either the production or development
! 704: clusters, then the certificate will need to be signed by the official
! 705: LON-CAPA Certificate Authority (CA). If you will be running your own
! 706: cluster then the cluster will need to create its own CA.
! 707:
! 708: END
! 709: }
! 710:
! 711: sub get_country {
! 712: my ($hostname) = @_;
! 713: # get Country
! 714: my ($posscountry,$country);
! 715: if ($hostname =~ /\.(edu|com|org)$/) {
! 716: $posscountry = 'us';
! 717: } else {
! 718: ($posscountry) = ($hostname =~ /\.(a-z){2}$/);
! 719: }
! 720: if ($posscountry) {
! 721: my $countrydesc = &Locale::Country::code2country($posscountry);
! 722: if ($countrydesc eq '') {
! 723: undef($posscountry);
! 724: }
! 725: }
! 726:
! 727: my $flag=0;
! 728: while (!$flag) {
! 729: if ($posscountry) {
! 730: $posscountry = uc($posscountry);
! 731: print "ENTER TWO-LETTER COUNTRY CODE [$posscountry]:\n";
! 732: } else {
! 733: print "ENTER TWO-LETTER COUNTRY CODE:\n";
! 734: }
! 735: my $choice=<>;
! 736: chomp($choice);
! 737: if ($choice ne '') {
! 738: if (&Locale::Country::code2country(lc($choice))) {
! 739: open(OUT,'>>/tmp/loncapa_updatequery.out');
! 740: print(OUT 'country'."\t".uc($choice)."\n");
! 741: close(OUT);
! 742: $country=uc($choice);
! 743: $flag=1;
! 744: } else {
! 745: print "Invalid input -- a valid two letter country code is required\n";
! 746: }
! 747: } elsif (($choice eq '') && ($posscountry ne '')) {
! 748: open(OUT,'>>/tmp/loncapa_updatequery.out');
! 749: print(OUT 'country'."\t".$posscountry."\n");
! 750: close(OUT);
! 751: $country = $posscountry;
! 752: $flag = 1;
! 753: } else {
! 754: print "Invalid input -- a country code is required\n";
! 755: }
! 756: }
! 757: return $country;
! 758: }
! 759:
! 760: sub get_state {
! 761: # get State or Province
! 762: my $flag=0;
! 763: my $state = '';
! 764: while (!$flag) {
! 765: print(<<END);
! 766:
! 767: ENTER STATE OR PROVINCE NAME:
! 768: END
! 769:
! 770: my $choice=<>;
! 771: chomp($choice);
! 772: if ($choice ne '') {
! 773: open(OUT,'>>/tmp/loncapa_updatequery.out');
! 774: print(OUT 'state'."\t".$choice."\n");
! 775: close(OUT);
! 776: $state=$choice;
! 777: $flag=1;
! 778: } else {
! 779: print "Invalid input (a state or province name is required).\n";
! 780: }
! 781: }
! 782: return $state;
! 783: }
! 784:
! 785: sub get_city {
! 786: # get City
! 787: my $flag=0;
! 788: my $city = '';
! 789: while (!$flag) {
! 790: print(<<END);
! 791:
! 792: ENTER CITY NAME:
! 793: END
! 794:
! 795: my $choice=<>;
! 796: chomp($choice);
! 797: if ($choice ne '') {
! 798: open(OUT,'>>/tmp/loncapa_updatequery.out');
! 799: print(OUT 'city'."\t".$choice."\n");
! 800: close(OUT);
! 801: $city=$choice;
! 802: $flag=1;
! 803: } else {
! 804: print "Invalid input (a city is required).\n";
! 805: }
! 806: }
! 807: return $city;
! 808: }
! 809:
! 810: sub confirm_locality {
! 811: my ($domainDescription,$country,$state,$city) = @_;
! 812: my $flag = 0;
! 813: while (!$flag) {
! 814: print(<<END);
! 815:
! 816: The domain description, country, state and city will be
! 817: used in the SSL certificates
! 818:
! 819: 1) Domain Description: $domainDescription
! 820: 2) Country: $country
! 821: 3) State or Province: $state
! 822: 4) City: $city
! 823: 5) Everything is correct up above
! 824:
! 825: ENTER A CHOICE OF 1-4 TO CHANGE, otherwise ENTER 5:
! 826: END
! 827: my $choice=<>;
! 828: chomp($choice);
! 829: if ($choice == 1) {
! 830: print(<<END);
! 831: 1) Domain Description: $domainDescription
! 832: ENTER NEW VALUE
! 833: END
! 834: my $choice2=<>;
! 835: chomp($choice2);
! 836: $domainDescription=$choice2;
! 837: } elsif ($choice == 2) {
! 838: print(<<END);
! 839: 2) Country: $country
! 840: ENTER NEW VALUE (this should be a two-character code, e,g, US, CA, DE)
! 841: END
! 842: my $choice2=<>;
! 843: chomp($choice2);
! 844: $country = uc($choice2);
! 845: } elsif ($choice == 3) {
! 846: print(<<END);
! 847: 3) State or Province: $state
! 848: ENTER NEW VALUE:
! 849: END
! 850: my $choice2=<>;
! 851: chomp($choice2);
! 852: $state=$choice2;
! 853: } elsif ($choice == 4) {
! 854: print(<<END);
! 855: 4) City: $city
! 856: ENTER NEW VALUE:
! 857: END
! 858: my $choice2=<>;
! 859: chomp($choice2);
! 860: $city=$choice2;
! 861: } elsif ($choice == 5) {
! 862: $flag=1;
! 863: $state =~ s{/}{ }g;
! 864: $city =~ s{/}{ }g;
! 865: $domainDescription =~ s{/}{ }g;
! 866: } else {
! 867: print "Invalid input.\n";
! 868: }
! 869: }
! 870: return ($domainDescription,$country,$state,$city);
! 871: }
! 872:
! 873: sub make_key {
! 874: my ($certsdir,$privkey,$sslkeypass) = @_;
! 875: # generate SSL key
! 876: if ($certsdir && $privkey) {
! 877: if (-f "$certsdir/lonKey.enc") {
! 878: my $mode = 0600;
! 879: chmod $mode, "$certsdir/lonKey.enc";
! 880: }
! 881: open(PIPE,"openssl genrsa -des3 -passout pass:$sslkeypass -out $certsdir/lonKey.enc 2048 2>&1 |");
! 882: close(PIPE);
! 883: if (-f "$certsdir/$privkey") {
! 884: my $mode = 0600;
! 885: chmod $mode, "$certsdir/$privkey";
! 886: }
! 887: open(PIPE,"openssl rsa -in $certsdir/lonKey.enc -passin pass:$sslkeypass -out $certsdir/$privkey -outform PEM |");
! 888: close(PIPE);
! 889: if (-f "$certsdir/lonKey.enc") {
! 890: my $mode = 0400;
! 891: chmod $mode, "$certsdir/lonKey.enc";
! 892: }
! 893: if (-f "$certsdir/$privkey") {
! 894: my $mode = 0400;
! 895: chmod $mode, "$certsdir/$privkey";
! 896: }
! 897: } else {
! 898: print "Key creation failed. Missing one or more of: certificates directory, key name\n";
! 899: }
! 900: }
! 901:
! 902: sub encrypt_key {
! 903: my ($certsdir,$privkey,$sslkeypass) = @_;
! 904: if ($certsdir && $privkey) {
! 905: if ((-f "$certsdir/$privkey") && (!-f "$certsdir/lonKey.enc")) {
! 906: open(PIPE,"openssl rsa -des3 -in $certsdir/$privkey -out $certsdir/lonKey.enc |");
! 907: }
! 908: }
! 909: return;
! 910: }
! 911:
! 912: sub make_host_csr {
! 913: my ($certsdir,$sslkeypass,$connectcsr,$connectsubj) = @_;
! 914: # generate SSL csr for hostID
! 915: if ($certsdir && $connectcsr && $connectsubj) {
! 916: open(PIPE,"openssl req -key $certsdir/lonKey.enc -passin pass:$sslkeypass -new -batch -subj \"$connectsubj\" -out $certsdir/$connectcsr |");
! 917: close(PIPE);
! 918: } else {
! 919: print "Creation of certificate signing request failed. Missing one or more of: certificates directory, CSR name, or locality information.\n";
! 920: }
! 921: }
! 922:
! 923: sub make_hostname_csr {
! 924: my ($certsdir,$sslkeypass,$replicatecsr,$replicatesubj) = @_;
! 925: # generate SSL csr for internal hostname
! 926: if ($certsdir && $replicatecsr && $replicatesubj) {
! 927: open(PIPE,"openssl req -key $certsdir/lonKey.enc -passin pass:$sslkeypass -new -batch -subj \"$replicatesubj\" -out $certsdir/$replicatecsr |");
! 928: close(PIPE);
! 929: } else {
! 930: print "Creation of certificate signing request failed. Missing one or more of: certificates directory, CSR name, or locality information.\n";
! 931: }
! 932: }
! 933:
! 934: sub get_mail {
! 935: my $email;
! 936: my $flag=0;
! 937: # get E-mail Address
! 938: while (!$flag) {
! 939: print(<<END);
! 940:
! 941: An e-mail address to be included with certificate signing requests is needed.
! 942: After signing by the Certificate Authority, the signed certificate(s) will
! 943: be returned to this e-mail address.
! 944: ENTER E-MAIL ADDRESS
! 945: END
! 946: my $choice=<>;
! 947: chomp($choice);
! 948: if (($choice ne '') && ($choice =~ /^[^\@]+\@[^\@]+$/)) {
! 949: $email=$choice;
! 950: $flag=1;
! 951: } else {
! 952: print "Invalid input (a valid email address is required).\n";
! 953: }
! 954: }
! 955: return $email;
! 956: }
! 957:
! 958:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>