xref: /titanic_54/usr/src/tools/codesign/signit.pl (revision 23259b79afff8cc5e183c5be57e05120f378fa72)
1*23259b79Srotondo#!/usr/perl5/bin/perl
2*23259b79Srotondo#
3*23259b79Srotondo# CDDL HEADER START
4*23259b79Srotondo#
5*23259b79Srotondo# The contents of this file are subject to the terms of the
6*23259b79Srotondo# Common Development and Distribution License (the "License").
7*23259b79Srotondo# You may not use this file except in compliance with the License.
8*23259b79Srotondo#
9*23259b79Srotondo# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*23259b79Srotondo# or http://www.opensolaris.org/os/licensing.
11*23259b79Srotondo# See the License for the specific language governing permissions
12*23259b79Srotondo# and limitations under the License.
13*23259b79Srotondo#
14*23259b79Srotondo# When distributing Covered Code, include this CDDL HEADER in each
15*23259b79Srotondo# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*23259b79Srotondo# If applicable, add the following below this CDDL HEADER, with the
17*23259b79Srotondo# fields enclosed by brackets "[]" replaced with your own identifying
18*23259b79Srotondo# information: Portions Copyright [yyyy] [name of copyright owner]
19*23259b79Srotondo#
20*23259b79Srotondo# CDDL HEADER END
21*23259b79Srotondo#
22*23259b79Srotondo#
23*23259b79Srotondo# ident	"%Z%%M%	%I%	%E% SMI"
24*23259b79Srotondo#
25*23259b79Srotondo# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
26*23259b79Srotondo# Use is subject to license terms.
27*23259b79Srotondo#
28*23259b79Srotondo
29*23259b79Srotondo# signit [-q] [-i dir][-o dir] [-l user]
30*23259b79Srotondo#
31*23259b79Srotondo# Client program for use with code signing server.
32*23259b79Srotondo# Reads a list of signing credential names and file pathnames
33*23259b79Srotondo# from standard input. Each file is read from the input directory,
34*23259b79Srotondo# sent to the signing server, signed with the specified credential,
35*23259b79Srotondo# and written to the output directory.
36*23259b79Srotondo#
37*23259b79Srotondo# Options:
38*23259b79Srotondo#	-q	quiet operation: avoid printing files successfully signed
39*23259b79Srotondo#	-i dir	input directory (defaults to current dir)
40*23259b79Srotondo#	-o dir	output directory (defautls to input dir)
41*23259b79Srotondo#	-l user	user account on signing server (defaults to current user)
42*23259b79Srotondo#
43*23259b79Srotondo# The CODESIGN_SERVER environment variable can be used to
44*23259b79Srotondo# specify the hostname or IP address of the signing server
45*23259b79Srotondo# (defaults to quill.sfbay).
46*23259b79Srotondo
47*23259b79Srotondouse strict;
48*23259b79Srotondouse Cwd;
49*23259b79Srotondouse File::Temp 'tempdir';
50*23259b79Srotondouse Getopt::Std;
51*23259b79Srotondouse IPC::Open2;
52*23259b79Srotondo
53*23259b79Srotondo#
54*23259b79Srotondo# Global variables
55*23259b79Srotondo#
56*23259b79Srotondomy ($Indir, $Outdir);	# Input and output directories (may be the same)
57*23259b79Srotondomy $Server;		# Signing server hostname
58*23259b79Srotondomy $Quiet;		# Suppress printing each file successfully signed
59*23259b79Srotondomy ($pid);		# Process id for ssh client
60*23259b79Srotondomy @cred_rules;		# Array of path prefixes and credentials to use
61*23259b79Srotondomy $Tmpdir = tempdir(CLEANUP => 1);	# Temporary directory
62*23259b79Srotondomy $Warnings = 0;	# Count of warnings returned
63*23259b79Srotondo
64*23259b79Srotondo
65*23259b79Srotondo#
66*23259b79Srotondo# Main program
67*23259b79Srotondo#
68*23259b79Srotondo
69*23259b79Srotondo$Server = $ENV{CODESIGN_SERVER} || "quill.sfbay";
70*23259b79Srotondo
71*23259b79Srotondo# Get command-line arguments
72*23259b79Srotondoour($opt_c, $opt_i, $opt_o, $opt_l, $opt_q);
73*23259b79Srotondoif (!getopts("i:o:c:l:q")) {
74*23259b79Srotondo	die "Usage: $0 [-i dir] [-o dir] [-l user]\n";
75*23259b79Srotondo}
76*23259b79Srotondo$Quiet = $opt_q;
77*23259b79Srotondo
78*23259b79Srotondo# Get input/output directories
79*23259b79Srotondo$Indir = $opt_i || getcwd();	# default to current dir
80*23259b79Srotondo$Outdir = $opt_o || $Indir;	# default to input dir
81*23259b79Srotondo$Indir = getcwd() . "/$Indir" if (substr($Indir, 0, 1) ne "/");
82*23259b79Srotondo$Outdir = getcwd() . "/$Outdir" if (substr($Outdir, 0, 1) ne "/");
83*23259b79Srotondo
84*23259b79Srotondo# Create ssh connection to server
85*23259b79Srotondomy(@args);
86*23259b79Srotondoif (defined($opt_l)) {
87*23259b79Srotondo	push @args, "-l", $opt_l;
88*23259b79Srotondo}
89*23259b79Srotondopush @args, "-s", $Server, "codesign";
90*23259b79Srotondo$pid = open2(*SRV_OUT, *SRV_IN, "/usr/bin/ssh", @args) or
91*23259b79Srotondo	die "Can't start server\n";
92*23259b79Srotondoselect(SRV_IN); $| = 1; select(STDOUT);	# unbuffered writes
93*23259b79Srotondo
94*23259b79Srotondo# Sign each file with the specified credential
95*23259b79Srotondochdir($Indir);
96*23259b79Srotondowhile (<>) {
97*23259b79Srotondo	my ($cred, $path) = split;
98*23259b79Srotondo
99*23259b79Srotondo	sign_file($cred, $path);
100*23259b79Srotondo}
101*23259b79Srotondoexit($Warnings > 0);
102*23259b79Srotondo
103*23259b79Srotondo#
104*23259b79Srotondo# END()
105*23259b79Srotondo#
106*23259b79Srotondo# Clean up after normal or abnormal exit.
107*23259b79Srotondo#
108*23259b79Srotondosub END {
109*23259b79Srotondo	close(SRV_IN);
110*23259b79Srotondo	close(SRV_OUT);
111*23259b79Srotondo	waitpid($pid, 0) if ($pid);
112*23259b79Srotondo}
113*23259b79Srotondo
114*23259b79Srotondo#
115*23259b79Srotondo# debug(msg)
116*23259b79Srotondo#
117*23259b79Srotondo# Print debug message to standard error.
118*23259b79Srotondo#
119*23259b79Srotondosub debug {
120*23259b79Srotondo	print STDERR "### @_";
121*23259b79Srotondo}
122*23259b79Srotondo
123*23259b79Srotondo#
124*23259b79Srotondo# check_response(str)
125*23259b79Srotondo#
126*23259b79Srotondo# Validate response from server. Print messages for warnings or errors,
127*23259b79Srotondo# and exit in the case of an error. If the response indicates a successful
128*23259b79Srotondo# signing operation, return the size of the output data.
129*23259b79Srotondo#
130*23259b79Srotondosub check_response {
131*23259b79Srotondo	my ($str) = @_;
132*23259b79Srotondo
133*23259b79Srotondo	if ($str =~ /^OK SIGN (\d+)/) {
134*23259b79Srotondo		return ($1);
135*23259b79Srotondo	}
136*23259b79Srotondo	elsif ($str =~ /^OK/) {
137*23259b79Srotondo		return (0);
138*23259b79Srotondo	}
139*23259b79Srotondo	elsif ($str =~ /^WARNING/) {
140*23259b79Srotondo		print STDERR $str;
141*23259b79Srotondo		$Warnings++;
142*23259b79Srotondo		return (-1);
143*23259b79Srotondo	}
144*23259b79Srotondo	elsif ($str =~ /^ERROR/) {
145*23259b79Srotondo		print STDERR $str;
146*23259b79Srotondo		exit(1);
147*23259b79Srotondo	}
148*23259b79Srotondo	else {
149*23259b79Srotondo		print STDERR "Unrecognized response\n";
150*23259b79Srotondo		exit(1);
151*23259b79Srotondo	}
152*23259b79Srotondo}
153*23259b79Srotondo
154*23259b79Srotondo#
155*23259b79Srotondo# sign_file(credential, filename)
156*23259b79Srotondo#
157*23259b79Srotondo# Send the file to the server for signing. Package the file into a
158*23259b79Srotondo# ZIP archive, send to the server, and extract the ZIP archive that
159*23259b79Srotondo# is returned. The input ZIP archive always contains a single file,
160*23259b79Srotondo# but the returned archive may contain one or more files.
161*23259b79Srotondo#
162*23259b79Srotondosub sign_file {
163*23259b79Srotondo	my ($cred, $path) = @_;
164*23259b79Srotondo	my ($res, $size);
165*23259b79Srotondo
166*23259b79Srotondo	$path =~ s:^\./::g; # remove leading "./"
167*23259b79Srotondo	unlink("$Tmpdir/in.zip");
168*23259b79Srotondo	system("cd $Indir; /usr/bin/zip -q $Tmpdir/in.zip $path");
169*23259b79Srotondo
170*23259b79Srotondo	sendfile("$Tmpdir/in.zip", "$cred $path") || return;
171*23259b79Srotondo
172*23259b79Srotondo	$res = <SRV_OUT>;
173*23259b79Srotondo	$size = check_response($res);
174*23259b79Srotondo	if ($size > 0) {
175*23259b79Srotondo		recvfile("$Tmpdir/out.zip", $size) || return;
176*23259b79Srotondo
177*23259b79Srotondo		if (system("cd $Outdir; /usr/bin/unzip -qo $Tmpdir/out.zip")) {
178*23259b79Srotondo			$Warnings++;
179*23259b79Srotondo		} else {
180*23259b79Srotondo			print "$cred\t$path\n" unless $Quiet;
181*23259b79Srotondo		}
182*23259b79Srotondo	}
183*23259b79Srotondo}
184*23259b79Srotondo
185*23259b79Srotondo#
186*23259b79Srotondo# sendfile(file, args)
187*23259b79Srotondo#
188*23259b79Srotondo# Send a ZIP archive file to the signing server. This involves
189*23259b79Srotondo# sending a SIGN command with the given arguments, followed by
190*23259b79Srotondo# the contents of the archive itself.
191*23259b79Srotondo#
192*23259b79Srotondosub sendfile {
193*23259b79Srotondo	my ($file, $args) = @_;
194*23259b79Srotondo	my ($size, $bytes);
195*23259b79Srotondo
196*23259b79Srotondo	$size = -s $file;
197*23259b79Srotondo	print SRV_IN "SIGN $size $args\n";
198*23259b79Srotondo	if (!open(F, "<$file")) {
199*23259b79Srotondo		print STDERR "$file: $!\n";
200*23259b79Srotondo		return (0);
201*23259b79Srotondo	}
202*23259b79Srotondo	read(F, $bytes, $size);
203*23259b79Srotondo	close(F);
204*23259b79Srotondo	if (!syswrite(SRV_IN, $bytes, $size)) {
205*23259b79Srotondo		print STDERR "Can't send to server: $!\n";
206*23259b79Srotondo		return (0);
207*23259b79Srotondo	}
208*23259b79Srotondo	return (1);
209*23259b79Srotondo}
210*23259b79Srotondo
211*23259b79Srotondo#
212*23259b79Srotondo# recvfile(file, size)
213*23259b79Srotondo#
214*23259b79Srotondo# Receive a ZIP archive from the signing server. The caller
215*23259b79Srotondo# provides the size argument previously obtained from the
216*23259b79Srotondo# server response.
217*23259b79Srotondo#
218*23259b79Srotondosub recvfile {
219*23259b79Srotondo	my ($file, $size) = @_;
220*23259b79Srotondo	my $bytes;
221*23259b79Srotondo
222*23259b79Srotondo	if (!read(SRV_OUT, $bytes, $size)) {
223*23259b79Srotondo		print STDERR "Can't read from server: $!\n";
224*23259b79Srotondo		return (0);
225*23259b79Srotondo	}
226*23259b79Srotondo	if (!open(F, ">$file")) {
227*23259b79Srotondo		print STDERR "$file: $!\n";
228*23259b79Srotondo		return (0);
229*23259b79Srotondo	}
230*23259b79Srotondo	syswrite(F, $bytes, $size);
231*23259b79Srotondo	close(F);
232*23259b79Srotondo	return (1);
233*23259b79Srotondo}
234