xref: /illumos-gate/usr/src/tools/codesign/signit.pl (revision 2210853d)
123259b79Srotondo#!/usr/perl5/bin/perl
223259b79Srotondo#
323259b79Srotondo# CDDL HEADER START
423259b79Srotondo#
523259b79Srotondo# The contents of this file are subject to the terms of the
623259b79Srotondo# Common Development and Distribution License (the "License").
723259b79Srotondo# You may not use this file except in compliance with the License.
823259b79Srotondo#
923259b79Srotondo# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1023259b79Srotondo# or http://www.opensolaris.org/os/licensing.
1123259b79Srotondo# See the License for the specific language governing permissions
1223259b79Srotondo# and limitations under the License.
1323259b79Srotondo#
1423259b79Srotondo# When distributing Covered Code, include this CDDL HEADER in each
1523259b79Srotondo# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1623259b79Srotondo# If applicable, add the following below this CDDL HEADER, with the
1723259b79Srotondo# fields enclosed by brackets "[]" replaced with your own identifying
1823259b79Srotondo# information: Portions Copyright [yyyy] [name of copyright owner]
1923259b79Srotondo#
2023259b79Srotondo# CDDL HEADER END
2123259b79Srotondo#
2223259b79Srotondo#
2323259b79Srotondo# ident	"%Z%%M%	%I%	%E% SMI"
2423259b79Srotondo#
2523259b79Srotondo# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2623259b79Srotondo# Use is subject to license terms.
2723259b79Srotondo#
2823259b79Srotondo
2923259b79Srotondo# signit [-q] [-i dir][-o dir] [-l user]
3023259b79Srotondo#
3123259b79Srotondo# Client program for use with code signing server.
3223259b79Srotondo# Reads a list of signing credential names and file pathnames
3323259b79Srotondo# from standard input. Each file is read from the input directory,
3423259b79Srotondo# sent to the signing server, signed with the specified credential,
3523259b79Srotondo# and written to the output directory.
3623259b79Srotondo#
3723259b79Srotondo# Options:
3823259b79Srotondo#	-q	quiet operation: avoid printing files successfully signed
3923259b79Srotondo#	-i dir	input directory (defaults to current dir)
4023259b79Srotondo#	-o dir	output directory (defautls to input dir)
4123259b79Srotondo#	-l user	user account on signing server (defaults to current user)
4223259b79Srotondo#
4323259b79Srotondo# The CODESIGN_SERVER environment variable can be used to
4423259b79Srotondo# specify the hostname or IP address of the signing server
4523259b79Srotondo# (defaults to quill.sfbay).
4623259b79Srotondo
4723259b79Srotondouse strict;
4823259b79Srotondouse Cwd;
4923259b79Srotondouse File::Temp 'tempdir';
5023259b79Srotondouse Getopt::Std;
5123259b79Srotondouse IPC::Open2;
5223259b79Srotondo
5323259b79Srotondo#
5423259b79Srotondo# Global variables
5523259b79Srotondo#
5623259b79Srotondomy ($Indir, $Outdir);	# Input and output directories (may be the same)
5723259b79Srotondomy $Server;		# Signing server hostname
5823259b79Srotondomy $Quiet;		# Suppress printing each file successfully signed
5923259b79Srotondomy ($pid);		# Process id for ssh client
6023259b79Srotondomy @cred_rules;		# Array of path prefixes and credentials to use
6123259b79Srotondomy $Tmpdir = tempdir(CLEANUP => 1);	# Temporary directory
6223259b79Srotondomy $Warnings = 0;	# Count of warnings returned
6323259b79Srotondo
6423259b79Srotondo
6523259b79Srotondo#
6623259b79Srotondo# Main program
6723259b79Srotondo#
6823259b79Srotondo
6923259b79Srotondo$Server = $ENV{CODESIGN_SERVER} || "quill.sfbay";
7023259b79Srotondo
7123259b79Srotondo# Get command-line arguments
7223259b79Srotondoour($opt_c, $opt_i, $opt_o, $opt_l, $opt_q);
7323259b79Srotondoif (!getopts("i:o:c:l:q")) {
7423259b79Srotondo	die "Usage: $0 [-i dir] [-o dir] [-l user]\n";
7523259b79Srotondo}
7623259b79Srotondo$Quiet = $opt_q;
7723259b79Srotondo
7823259b79Srotondo# Get input/output directories
7923259b79Srotondo$Indir = $opt_i || getcwd();	# default to current dir
8023259b79Srotondo$Outdir = $opt_o || $Indir;	# default to input dir
8123259b79Srotondo$Indir = getcwd() . "/$Indir" if (substr($Indir, 0, 1) ne "/");
8223259b79Srotondo$Outdir = getcwd() . "/$Outdir" if (substr($Outdir, 0, 1) ne "/");
8323259b79Srotondo
84*2210853dSjohnz# Ignore SIGPIPE to allow proper error messages
85*2210853dSjohnz$SIG{PIPE} = 'IGNORE';
86*2210853dSjohnz
8723259b79Srotondo# Create ssh connection to server
8823259b79Srotondomy(@args);
8923259b79Srotondoif (defined($opt_l)) {
9023259b79Srotondo	push @args, "-l", $opt_l;
9123259b79Srotondo}
9223259b79Srotondopush @args, "-s", $Server, "codesign";
9323259b79Srotondo$pid = open2(*SRV_OUT, *SRV_IN, "/usr/bin/ssh", @args) or
94*2210853dSjohnz	die "ERROR Connection to server $Server failed\n";
9523259b79Srotondoselect(SRV_IN); $| = 1; select(STDOUT);	# unbuffered writes
9623259b79Srotondo
9723259b79Srotondo# Sign each file with the specified credential
9823259b79Srotondochdir($Indir);
9923259b79Srotondowhile (<>) {
10023259b79Srotondo	my ($cred, $path) = split;
10123259b79Srotondo
10223259b79Srotondo	sign_file($cred, $path);
10323259b79Srotondo}
10423259b79Srotondoexit($Warnings > 0);
10523259b79Srotondo
10623259b79Srotondo#
10723259b79Srotondo# END()
10823259b79Srotondo#
10923259b79Srotondo# Clean up after normal or abnormal exit.
11023259b79Srotondo#
11123259b79Srotondosub END {
112*2210853dSjohnz	my $old_status = $?;
113*2210853dSjohnz
114*2210853dSjohnz	$? = 0;
11523259b79Srotondo	close(SRV_IN);
11623259b79Srotondo	close(SRV_OUT);
11723259b79Srotondo	waitpid($pid, 0) if ($pid);
118*2210853dSjohnz	if ($?) {
119*2210853dSjohnz		print STDERR "ERROR Connection to server $Server failed\n";
120*2210853dSjohnz		$? = 1;
121*2210853dSjohnz	}
122*2210853dSjohnz	$? = $old_status if ($? == 0);
12323259b79Srotondo}
12423259b79Srotondo
12523259b79Srotondo#
12623259b79Srotondo# debug(msg)
12723259b79Srotondo#
12823259b79Srotondo# Print debug message to standard error.
12923259b79Srotondo#
13023259b79Srotondosub debug {
13123259b79Srotondo	print STDERR "### @_";
13223259b79Srotondo}
13323259b79Srotondo
13423259b79Srotondo#
13523259b79Srotondo# check_response(str)
13623259b79Srotondo#
13723259b79Srotondo# Validate response from server. Print messages for warnings or errors,
13823259b79Srotondo# and exit in the case of an error. If the response indicates a successful
13923259b79Srotondo# signing operation, return the size of the output data.
14023259b79Srotondo#
14123259b79Srotondosub check_response {
14223259b79Srotondo	my ($str) = @_;
14323259b79Srotondo
14423259b79Srotondo	if ($str =~ /^OK SIGN (\d+)/) {
14523259b79Srotondo		return ($1);
14623259b79Srotondo	}
14723259b79Srotondo	elsif ($str =~ /^OK/) {
14823259b79Srotondo		return (0);
14923259b79Srotondo	}
15023259b79Srotondo	elsif ($str =~ /^WARNING/) {
15123259b79Srotondo		print STDERR $str;
15223259b79Srotondo		$Warnings++;
15323259b79Srotondo		return (-1);
15423259b79Srotondo	}
15523259b79Srotondo	elsif ($str =~ /^ERROR/) {
15623259b79Srotondo		print STDERR $str;
15723259b79Srotondo		exit(1);
15823259b79Srotondo	}
15923259b79Srotondo	else {
160*2210853dSjohnz		printf STDERR "ERROR Protocol failure (%d)\n", length($str);
16123259b79Srotondo		exit(1);
16223259b79Srotondo	}
16323259b79Srotondo}
16423259b79Srotondo
16523259b79Srotondo#
16623259b79Srotondo# sign_file(credential, filename)
16723259b79Srotondo#
16823259b79Srotondo# Send the file to the server for signing. Package the file into a
16923259b79Srotondo# ZIP archive, send to the server, and extract the ZIP archive that
17023259b79Srotondo# is returned. The input ZIP archive always contains a single file,
17123259b79Srotondo# but the returned archive may contain one or more files.
17223259b79Srotondo#
17323259b79Srotondosub sign_file {
17423259b79Srotondo	my ($cred, $path) = @_;
17523259b79Srotondo	my ($res, $size);
17623259b79Srotondo
17723259b79Srotondo	$path =~ s:^\./::g; # remove leading "./"
17823259b79Srotondo	unlink("$Tmpdir/in.zip");
17923259b79Srotondo	system("cd $Indir; /usr/bin/zip -q $Tmpdir/in.zip $path");
18023259b79Srotondo
18123259b79Srotondo	sendfile("$Tmpdir/in.zip", "$cred $path") || return;
18223259b79Srotondo
18323259b79Srotondo	$res = <SRV_OUT>;
18423259b79Srotondo	$size = check_response($res);
18523259b79Srotondo	if ($size > 0) {
18623259b79Srotondo		recvfile("$Tmpdir/out.zip", $size) || return;
18723259b79Srotondo
18823259b79Srotondo		if (system("cd $Outdir; /usr/bin/unzip -qo $Tmpdir/out.zip")) {
18923259b79Srotondo			$Warnings++;
19023259b79Srotondo		} else {
19123259b79Srotondo			print "$cred\t$path\n" unless $Quiet;
19223259b79Srotondo		}
19323259b79Srotondo	}
19423259b79Srotondo}
19523259b79Srotondo
19623259b79Srotondo#
19723259b79Srotondo# sendfile(file, args)
19823259b79Srotondo#
19923259b79Srotondo# Send a ZIP archive file to the signing server. This involves
20023259b79Srotondo# sending a SIGN command with the given arguments, followed by
20123259b79Srotondo# the contents of the archive itself.
20223259b79Srotondo#
20323259b79Srotondosub sendfile {
20423259b79Srotondo	my ($file, $args) = @_;
20523259b79Srotondo	my ($size, $bytes);
20623259b79Srotondo
20723259b79Srotondo	$size = -s $file;
20823259b79Srotondo	print SRV_IN "SIGN $size $args\n";
20923259b79Srotondo	if (!open(F, "<$file")) {
21023259b79Srotondo		print STDERR "$file: $!\n";
21123259b79Srotondo		return (0);
21223259b79Srotondo	}
21323259b79Srotondo	read(F, $bytes, $size);
21423259b79Srotondo	close(F);
21523259b79Srotondo	if (!syswrite(SRV_IN, $bytes, $size)) {
21623259b79Srotondo		print STDERR "Can't send to server: $!\n";
21723259b79Srotondo		return (0);
21823259b79Srotondo	}
21923259b79Srotondo	return (1);
22023259b79Srotondo}
22123259b79Srotondo
22223259b79Srotondo#
22323259b79Srotondo# recvfile(file, size)
22423259b79Srotondo#
22523259b79Srotondo# Receive a ZIP archive from the signing server. The caller
22623259b79Srotondo# provides the size argument previously obtained from the
22723259b79Srotondo# server response.
22823259b79Srotondo#
22923259b79Srotondosub recvfile {
23023259b79Srotondo	my ($file, $size) = @_;
23123259b79Srotondo	my $bytes;
23223259b79Srotondo
23323259b79Srotondo	if (!read(SRV_OUT, $bytes, $size)) {
23423259b79Srotondo		print STDERR "Can't read from server: $!\n";
23523259b79Srotondo		return (0);
23623259b79Srotondo	}
23723259b79Srotondo	if (!open(F, ">$file")) {
23823259b79Srotondo		print STDERR "$file: $!\n";
23923259b79Srotondo		return (0);
24023259b79Srotondo	}
24123259b79Srotondo	syswrite(F, $bytes, $size);
24223259b79Srotondo	close(F);
24323259b79Srotondo	return (1);
24423259b79Srotondo}
245