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