1 | #!/usr/bin/perl
|
---|
2 | #############################################################################
|
---|
3 | ##
|
---|
4 | ## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
5 | ## All rights reserved.
|
---|
6 | ## Contact: Nokia Corporation ([email protected])
|
---|
7 | ##
|
---|
8 | ## This file is part of the S60 port of the Qt Toolkit.
|
---|
9 | ##
|
---|
10 | ## $QT_BEGIN_LICENSE:LGPL$
|
---|
11 | ## Commercial Usage
|
---|
12 | ## Licensees holding valid Qt Commercial licenses may use this file in
|
---|
13 | ## accordance with the Qt Commercial License Agreement provided with the
|
---|
14 | ## Software or, alternatively, in accordance with the terms contained in
|
---|
15 | ## a written agreement between you and Nokia.
|
---|
16 | ##
|
---|
17 | ## GNU Lesser General Public License Usage
|
---|
18 | ## Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
19 | ## General Public License version 2.1 as published by the Free Software
|
---|
20 | ## Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
21 | ## packaging of this file. Please review the following information to
|
---|
22 | ## ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
23 | ## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
24 | ##
|
---|
25 | ## In addition, as a special exception, Nokia gives you certain additional
|
---|
26 | ## rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
27 | ## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
28 | ##
|
---|
29 | ## GNU General Public License Usage
|
---|
30 | ## Alternatively, this file may be used under the terms of the GNU
|
---|
31 | ## General Public License version 3.0 as published by the Free Software
|
---|
32 | ## Foundation and appearing in the file LICENSE.GPL included in the
|
---|
33 | ## packaging of this file. Please review the following information to
|
---|
34 | ## ensure the GNU General Public License version 3.0 requirements will be
|
---|
35 | ## met: http://www.gnu.org/copyleft/gpl.html.
|
---|
36 | ##
|
---|
37 | ## If you have questions regarding the use of this file, please contact
|
---|
38 | ## Nokia at [email protected].
|
---|
39 | ## $QT_END_LICENSE$
|
---|
40 | ##
|
---|
41 | #############################################################################
|
---|
42 |
|
---|
43 | #######################################################################
|
---|
44 | #
|
---|
45 | # A script for setting binary capabilities based on .pkg file contents.
|
---|
46 | #
|
---|
47 | #######################################################################
|
---|
48 |
|
---|
49 | #
|
---|
50 | # Note: Please make sure to output all changes done to the pkg file in a print statements
|
---|
51 | # starting with "Patching: " to ease integration into IDEs!
|
---|
52 | #
|
---|
53 |
|
---|
54 | use File::Copy;
|
---|
55 | use File::Spec;
|
---|
56 |
|
---|
57 | sub Usage() {
|
---|
58 | print("This script can be used to set capabilities of all binaries\n");
|
---|
59 | print("specified for deployment in a .pkg file.\n");
|
---|
60 | print("If no capabilities are given, the binaries will be given the\n");
|
---|
61 | print("capabilities supported by self-signed certificates.\n\n");
|
---|
62 | print(" *** NOTE: If *_template.pkg file is given and one is using symbian-abld or\n");
|
---|
63 | print(" symbian-sbsv2 platform, 'target-platform' is REQUIRED. ***\n\n");
|
---|
64 | print(" *** NOTE2: When patching gcce binaries built with symbian-sbsv2 toolchain,\n");
|
---|
65 | print(" armv5 must be specified as platform.\n");
|
---|
66 | print("\nUsage: patch_capabilities.pl [-c] pkg_filename [target-platform [capability list]]\n");
|
---|
67 | print("\nE.g. patch_capabilities.pl myapp_template.pkg release-armv5 \"All -TCB\"\n");
|
---|
68 | print("\nThe parameter -c can be used to just check if package is compatible with self-signing\n");
|
---|
69 | print("without actually doing any patching.\n");
|
---|
70 | print("Explicit capability list cannot be used with -c parameter.\n");
|
---|
71 | exit();
|
---|
72 | }
|
---|
73 |
|
---|
74 | sub trim($) {
|
---|
75 | my $string = shift;
|
---|
76 | $string =~ s/^\s+//;
|
---|
77 | $string =~ s/\s+$//;
|
---|
78 | return $string;
|
---|
79 | }
|
---|
80 |
|
---|
81 | my $epocroot = $ENV{EPOCROOT};
|
---|
82 | my $epocToolsDir = "";
|
---|
83 | if ($epocroot ne "") {
|
---|
84 | $epocroot =~ s,\\,/,g;
|
---|
85 | if ($epocroot =~ m,[^/]$,) {
|
---|
86 | $epocroot = $epocroot."/";
|
---|
87 | }
|
---|
88 | $epocToolsDir = "${epocroot}epoc32/tools/";
|
---|
89 | }
|
---|
90 |
|
---|
91 | my $nullDevice = "/dev/null";
|
---|
92 | $nullDevice = "NUL" if ($^O =~ /MSWin/);
|
---|
93 |
|
---|
94 | my @capabilitiesToAllow = ("LocalServices", "NetworkServices", "ReadUserData", "UserEnvironment", "WriteUserData", "Location");
|
---|
95 | my @capabilitiesSpecified = ();
|
---|
96 |
|
---|
97 | # If arguments were given to the script,
|
---|
98 | if (@ARGV)
|
---|
99 | {
|
---|
100 | # Parse the first given script argument as a ".pkg" file name.
|
---|
101 | my $pkgFileName = shift(@ARGV);
|
---|
102 | my $justCheck = "";
|
---|
103 | my $msgPrefix = "Patching:";
|
---|
104 |
|
---|
105 | if ($pkgFileName eq "-c") {
|
---|
106 | $pkgFileName = shift(@ARGV);
|
---|
107 | $justCheck = true;
|
---|
108 | $msgPrefix = "Warning:";
|
---|
109 | }
|
---|
110 |
|
---|
111 | # These variables will only be set for template .pkg files.
|
---|
112 | my $target;
|
---|
113 | my $platform;
|
---|
114 |
|
---|
115 | # Check if using template .pkg and set target/platform variables
|
---|
116 | if (($pkgFileName =~ m|_template\.pkg$|i) && -r($pkgFileName))
|
---|
117 | {
|
---|
118 | my $targetplatform;
|
---|
119 | my $templateFile;
|
---|
120 | my $templateContents;
|
---|
121 | open($templateFile, "< $pkgFileName") or die ("Could not open $pkgFileName");
|
---|
122 | $templateContents = <$templateFile>;
|
---|
123 | close($templateFile);
|
---|
124 | unless (($targetplatform = shift(@ARGV)) || $templateContents !~ /\$\(PLATFORM\)/)
|
---|
125 | {
|
---|
126 | Usage();
|
---|
127 | }
|
---|
128 | $targetplatform = "-" if (!$targetplatform);
|
---|
129 | my @tmpvalues = split('-', $targetplatform);
|
---|
130 | $target = $tmpvalues[0];
|
---|
131 | $platform = $tmpvalues[1];
|
---|
132 |
|
---|
133 | # Convert visual target to real target (debug->udeb and release->urel)
|
---|
134 | $target =~ s/debug/udeb/i;
|
---|
135 | $target =~ s/release/urel/i;
|
---|
136 |
|
---|
137 | if (($platform =~ m/^gcce$/i) && ($ENV{SBS_HOME})) {
|
---|
138 | # Print a informative note in case suspected misuse is detected.
|
---|
139 | print "\nNote: You must use armv5 as platform when packaging gcce binaries built using symbian-sbsv2 mkspec.\n";
|
---|
140 | }
|
---|
141 | }
|
---|
142 |
|
---|
143 | # If the specified ".pkg" file exists (and can be read),
|
---|
144 | if (($pkgFileName =~ m|\.pkg$|i) && -r($pkgFileName))
|
---|
145 | {
|
---|
146 | print ("\n");
|
---|
147 | if ($justCheck) {
|
---|
148 | print ("Checking");
|
---|
149 | } else {
|
---|
150 | print ("Patching");
|
---|
151 | }
|
---|
152 | print (" package file and relevant binaries...\n");
|
---|
153 |
|
---|
154 | if (!$justCheck) {
|
---|
155 | # If there are more arguments given, parse them as capabilities.
|
---|
156 | if (@ARGV)
|
---|
157 | {
|
---|
158 | @capabilitiesSpecified = ();
|
---|
159 | while (@ARGV)
|
---|
160 | {
|
---|
161 | push (@capabilitiesSpecified, pop(@ARGV));
|
---|
162 | }
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | # Start with no binaries listed.
|
---|
167 | my @binaries = ();
|
---|
168 |
|
---|
169 | my $tempPkgFileName = $pkgFileName."_@@TEMP@@";
|
---|
170 |
|
---|
171 | if (!$justCheck) {
|
---|
172 | unlink($tempPkgFileName);
|
---|
173 | open (NEW_PKG, ">>".$tempPkgFileName);
|
---|
174 | }
|
---|
175 | open (PKG, "<".$pkgFileName);
|
---|
176 |
|
---|
177 | my $checkFailed = "";
|
---|
178 | my $somethingPatched = "";
|
---|
179 |
|
---|
180 | # Parse each line.
|
---|
181 | while (<PKG>)
|
---|
182 | {
|
---|
183 | my $line = $_;
|
---|
184 | my $newLine = $line;
|
---|
185 |
|
---|
186 | # Patch pkg UID if it's in protected range
|
---|
187 | if ($line =~ m/^\#.*\((0x[0-7][0-9a-fA-F]*)\).*$/)
|
---|
188 | {
|
---|
189 | my $oldUID = $1;
|
---|
190 | print ("$msgPrefix UID $oldUID is not compatible with self-signing!\n");
|
---|
191 |
|
---|
192 | if ($justCheck) {
|
---|
193 | $checkFailed = true;
|
---|
194 | } else {
|
---|
195 | my $newUID = $oldUID;
|
---|
196 | $newUID =~ s/0x./0xE/i;
|
---|
197 | $newLine =~ s/$oldUID/$newUID/;
|
---|
198 | print ("$msgPrefix Package UID changed to: $newUID.\n");
|
---|
199 | $somethingPatched = true;
|
---|
200 | }
|
---|
201 | }
|
---|
202 |
|
---|
203 | # If the line specifies a file, parse the source and destination locations.
|
---|
204 | if ($line =~ m|^ *\"([^\"]+)\"\s*\-\s*\"([^\"]+)\"|)
|
---|
205 | {
|
---|
206 | my $sourcePath = $1;
|
---|
207 |
|
---|
208 | # If the given file is a binary, check the target and binary type (+ the actual filename) from its path.
|
---|
209 | if ($sourcePath =~ m:\w+(\.dll|\.exe)$:i)
|
---|
210 | {
|
---|
211 | # Do preprocessing for template pkg,
|
---|
212 | # In case of template pkg target and platform variables are set
|
---|
213 | if(length($target) && length($platform))
|
---|
214 | {
|
---|
215 | $sourcePath =~ s/\$\(PLATFORM\)/$platform/gm;
|
---|
216 | $sourcePath =~ s/\$\(TARGET\)/$target/gm;
|
---|
217 | }
|
---|
218 |
|
---|
219 | if ($justCheck) {
|
---|
220 | push (@binaries, $sourcePath);
|
---|
221 | } else {
|
---|
222 | # Change the source file name (but only if not already patched)
|
---|
223 | my $patchedSourcePath = $sourcePath;
|
---|
224 | if ($patchedSourcePath !~ m/_patched_caps/)
|
---|
225 | {
|
---|
226 | $newLine =~ s/(^.*)(\.dll|\.exe)(.*)(\.dll|\.exe)/$1_patched_caps$2$3$4/i;
|
---|
227 | $patchedSourcePath =~ s/(^.*)(\.dll|\.exe)/$1_patched_caps$2/i;
|
---|
228 |
|
---|
229 | copy($sourcePath, $patchedSourcePath) or die "$sourcePath cannot be copied for patching.";
|
---|
230 | }
|
---|
231 | push (@binaries, $patchedSourcePath);
|
---|
232 | }
|
---|
233 | }
|
---|
234 | }
|
---|
235 |
|
---|
236 | print NEW_PKG $newLine;
|
---|
237 |
|
---|
238 | chomp ($line);
|
---|
239 | }
|
---|
240 |
|
---|
241 | close (PKG);
|
---|
242 | if (!$justCheck) {
|
---|
243 | close (NEW_PKG);
|
---|
244 |
|
---|
245 | unlink($pkgFileName);
|
---|
246 | rename($tempPkgFileName, $pkgFileName);
|
---|
247 | }
|
---|
248 | print ("\n");
|
---|
249 |
|
---|
250 | my $baseCommandToExecute = "${epocToolsDir}elftran -vid 0x0 -capability \"%s\" ";
|
---|
251 |
|
---|
252 | # Actually set the capabilities of the listed binaries.
|
---|
253 | foreach my $binaryPath(@binaries)
|
---|
254 | {
|
---|
255 | # Create the command line for setting the capabilities.
|
---|
256 | my ($binaryVolume, $binaryDirs, $binaryBaseName) = File::Spec->splitpath($binaryPath);
|
---|
257 | my $commandToExecute = $baseCommandToExecute;
|
---|
258 | my $executeNeeded = "";
|
---|
259 | if (@capabilitiesSpecified)
|
---|
260 | {
|
---|
261 | $commandToExecute = sprintf($baseCommandToExecute, join(" ", @capabilitiesSpecified));
|
---|
262 | $executeNeeded = true;
|
---|
263 | my $capString = join(" ", @capabilitiesSpecified);
|
---|
264 | print ("$msgPrefix Patching the the Vendor ID to 0 and the capabilities used to: \"$capString\" in \"$binaryBaseName\".\n");
|
---|
265 | } else {
|
---|
266 | # Test which capabilities are present and then restrict them to the allowed set.
|
---|
267 | # This avoid raising the capabilities of apps that already have none.
|
---|
268 | my $dllCaps;
|
---|
269 | open($dllCaps, "${epocToolsDir}elftran -dump s $binaryPath |") or die ("ERROR: Could not execute elftran");
|
---|
270 | my $capsFound = 0;
|
---|
271 | my $originalVid;
|
---|
272 | my @capabilitiesToSet;
|
---|
273 | my $capabilitiesToAllow = join(" ", @capabilitiesToAllow);
|
---|
274 | my @capabilitiesToDrop;
|
---|
275 | while (<$dllCaps>) {
|
---|
276 | if (/^Secure ID: ([0-7][0-9a-fA-F]*)$/) {
|
---|
277 | my $exeSid = $1;
|
---|
278 | if ($binaryBaseName =~ /\.exe$/) {
|
---|
279 | # Installer refuses to install protected executables in a self signed package, so abort if one is detected.
|
---|
280 | # We can't simply just patch the executable SID, as any registration resources executable uses will be linked to it via SID.
|
---|
281 | print ("$msgPrefix Executable with SID in the protected range (0x$exeSid) detected: \"$binaryBaseName\". A self-signed sis with protected executables is not supported.\n\n");
|
---|
282 | $checkFailed = true;
|
---|
283 | }
|
---|
284 | }
|
---|
285 | if (/^Vendor ID: ([0-9a-fA-F]*)$/) {
|
---|
286 | $originalVid = "$1";
|
---|
287 | }
|
---|
288 | if (!$capsFound) {
|
---|
289 | $capsFound = 1 if (/Capabilities:/);
|
---|
290 | } else {
|
---|
291 | $_ = trim($_);
|
---|
|
---|