#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# ident "%Z%%M% %I% %E% SMI"
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# Server program for code signing server
#
# This program implements an ssh-based service to add digital
# signatures to files. The sshd_config file on the server
# contains an entry like the following to invoke this program:
#
#
# The client program sends a ZIP archive of the file to be
# signed along with the name of a signing credential stored
# on the server. Each credential is a directory containing
# a public-key certificate, private key, and a script to
# perform the appropriate signing operation.
#
# This program unpacks the input ZIP archive, invokes the
# signing script for the specified credential, and sends
# back an output ZIP archive, which typically contains the
# (modified) input file but may also contain additional
# files created by the signing script.
use strict;
my $Session = $$;
#
# Main program
#
# Set up
$| = 1; # Flush output on every write
# Record user and client system
chomp($user);
audit("START User=$user Client=$client");
# Process signing requests
while (<STDIN>) {
if (/^SIGN (\d+) (\S+) (\S+)/) {
} else {
abnormal("WARNING Unknown command");
}
}
exit(0);
#
# get_credential(name)
#
# Verify that the user is allowed to use the named credential and
# return the path to the credential directory. If the user is not
# authorized to use the credential, return undef.
#
sub get_credential {
my $name = shift;
my $dir;
abnormal("WARNING Credential $name not available");
$dir = undef;
}
close(F);
return $dir;
}
#
# sign(size, cred, path)
#
# Sign an individual file.
#
sub sign {
# Read input file
# Check path for use of .. or absolute pathname
abnormal("WARNING Invalid path $path");
return;
}
}
# Get credential directory
# Create work area
# Read and unpack input ZIP archive
# Sign input file using credential-specific script
if ($? != 0) {
chomp($msg);
abnormal("WARNING $msg");
return;
}
# Pack output file(s) in ZIP archive and return
unlink("../out.zip");
chdir($Tmpdir);
# Audit successful signing
chomp($hash);
audit("SIGN $path $cred $hash");
}
#
# sendfile(file, path)
#
# Send a ZIP archive to the client. This involves sending
# an OK SIGN response that includes the file size, followed by
# the contents of the archive itself.
#
sub sendfile {
if (!open(F, "<$file")) {
abnormal("ERROR Internal read error");
return (0);
}
close(F);
print "OK SIGN $size $path\n";
return (1);
}
#
# recvfile(file, size)
#
# Receive a ZIP archive from the client. The caller
# provides the size argument previously obtained from the
# client request.
#
sub recvfile {
my $bytes;
abnormal("ERROR No input data");
return (0);
}
if (!open(F, ">$file")) {
abnormal("ERROR Internal write error");
return (0);
}
close(F);
return (1);
}
#
# audit(msg)
#
# Create an audit record. All records have this format:
# [date] [time] [session] [keyword] [other parameters]
# The keywords START and END mark the boundaries of a session.
#
sub audit {
my ($msg) = @_;
my $timestamp = sprintf("%04d-%02d-%02d %02d:%02d:%02d",
print AUDIT "$timestamp $Session $msg\n";
}
#
# abnormal(msg)
#
# Respond to an abnormal condition, which may be fatal (ERROR) or
# non-fatal (WARNING). Send the message to the audit error log
# and to the client program. Exit in case of fatal errors.
#
sub abnormal {
my $msg = shift;
print("$msg\n");
}
#
# END()
#
# Clean up prior to normal or abnormal exit.
#
sub END {
audit("END");
close(AUDIT);
chdir(""); # so $Tmpdir can be removed
}