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