blob: 4b03bc963db9075c600365dd925ff55269f0dac4 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <limits.h>
21#include <paths.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <unistd.h>
29
30#include <ctype.h>
31#include "cutils/misc.h"
32#include "cutils/properties.h"
33#include <dirent.h>
34#include <getopt.h>
35#include <linux/input.h>
36#include <signal.h>
37#include <sys/limits.h>
38#include <termios.h>
39#include <time.h>
40#include <sys/vfs.h>
41
42#include "tw_reboot.h"
43#include "bootloader.h"
44#include "common.h"
45#include "extra-functions.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040046#include "minuitwrp/minui.h"
47#include "minzip/DirUtil.h"
48#include "minzip/Zip.h"
49#include "recovery_ui.h"
50#include "roots.h"
51#include "data.h"
52#include "variables.h"
Dees_Troy657c3092012-09-10 20:32:10 -040053#include "mincrypt/rsa.h"
54#include "verifier.h"
55#include "mincrypt/sha.h"
56
57#ifndef PUBLIC_KEYS_FILE
58#define PUBLIC_KEYS_FILE "/res/keys"
59#endif
60#ifndef ASSUMED_UPDATE_BINARY_NAME
61#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
62#endif
63enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
Dees_Troy51a0e822012-09-05 15:24:24 -040064
65//kang system() from bionic/libc/unistd and rename it __system() so we can be even more hackish :)
66#undef _PATH_BSHELL
67#define _PATH_BSHELL "/sbin/sh"
68
Dees_Troy51a0e822012-09-05 15:24:24 -040069extern char **environ;
70
71int __system(const char *command) {
72 pid_t pid;
73 sig_t intsave, quitsave;
74 sigset_t mask, omask;
75 int pstat;
76 char *argp[] = {"sh", "-c", NULL, NULL};
77
78 if (!command) /* just checking... */
79 return(1);
80
81 argp[2] = (char *)command;
82
83 sigemptyset(&mask);
84 sigaddset(&mask, SIGCHLD);
85 sigprocmask(SIG_BLOCK, &mask, &omask);
86 switch (pid = vfork()) {
87 case -1: /* error */
88 sigprocmask(SIG_SETMASK, &omask, NULL);
89 return(-1);
90 case 0: /* child */
91 sigprocmask(SIG_SETMASK, &omask, NULL);
92 execve(_PATH_BSHELL, argp, environ);
93 _exit(127);
94 }
95
96 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
97 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
98 pid = waitpid(pid, (int *)&pstat, 0);
99 sigprocmask(SIG_SETMASK, &omask, NULL);
100 (void)bsd_signal(SIGINT, intsave);
101 (void)bsd_signal(SIGQUIT, quitsave);
102 return (pid == -1 ? -1 : pstat);
103}
104
105static struct pid {
106 struct pid *next;
107 FILE *fp;
108 pid_t pid;
109} *pidlist;
110
111FILE *__popen(const char *program, const char *type) {
112 struct pid * volatile cur;
113 FILE *iop;
114 int pdes[2];
115 pid_t pid;
116
117 if ((*type != 'r' && *type != 'w') || type[1] != '\0') {
118 errno = EINVAL;
119 return (NULL);
120 }
121
122 if ((cur = malloc(sizeof(struct pid))) == NULL)
123 return (NULL);
124
125 if (pipe(pdes) < 0) {
126 free(cur);
127 return (NULL);
128 }
129
130 switch (pid = vfork()) {
131 case -1: /* Error. */
132 (void)close(pdes[0]);
133 (void)close(pdes[1]);
134 free(cur);
135 return (NULL);
136 /* NOTREACHED */
137 case 0: /* Child. */
138 {
139 struct pid *pcur;
140 /*
141 * because vfork() instead of fork(), must leak FILE *,
142 * but luckily we are terminally headed for an execl()
143 */
144 for (pcur = pidlist; pcur; pcur = pcur->next)
145 close(fileno(pcur->fp));
146
147 if (*type == 'r') {
148 int tpdes1 = pdes[1];
149
150 (void) close(pdes[0]);
151 /*
152 * We must NOT modify pdes, due to the
153 * semantics of vfork.
154 */
155 if (tpdes1 != STDOUT_FILENO) {
156 (void)dup2(tpdes1, STDOUT_FILENO);
157 (void)close(tpdes1);
158 tpdes1 = STDOUT_FILENO;
159 }
160 } else {
161 (void)close(pdes[1]);
162 if (pdes[0] != STDIN_FILENO) {
163 (void)dup2(pdes[0], STDIN_FILENO);
164 (void)close(pdes[0]);
165 }
166 }
167 execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL);
168 _exit(127);
169 /* NOTREACHED */
170 }
171 }
172
173 /* Parent; assume fdopen can't fail. */
174 if (*type == 'r') {
175 iop = fdopen(pdes[0], type);
176 (void)close(pdes[1]);
177 } else {
178 iop = fdopen(pdes[1], type);
179 (void)close(pdes[0]);
180 }
181
182 /* Link into list of file descriptors. */
183 cur->fp = iop;
184 cur->pid = pid;
185 cur->next = pidlist;
186 pidlist = cur;
187
188 return (iop);
189}
190
191/*
192 * pclose --
193 * Pclose returns -1 if stream is not associated with a `popened' command,
194 * if already `pclosed', or waitpid returns an error.
195 */
196int __pclose(FILE *iop) {
197 struct pid *cur, *last;
198 int pstat;
199 pid_t pid;
200
201 /* Find the appropriate file pointer. */
202 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
203 if (cur->fp == iop)
204 break;
205
206 if (cur == NULL)
207 return (-1);
208
209 (void)fclose(iop);
210
211 do {
212 pid = waitpid(cur->pid, &pstat, 0);
213 } while (pid == -1 && errno == EINTR);
214
215 /* Remove the entry from the linked list. */
216 if (last == NULL)
217 pidlist = cur->next;
218 else
219 last->next = cur->next;
220 free(cur);
221
222 return (pid == -1 ? -1 : pstat);
223}
224
225char* sanitize_device_id(char* id) {
226 const char* whitelist ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-._";
227 char* c = id;
228 char* str = (int*) calloc(50, sizeof *id);
229 while (*c)
230 {
231 if (strchr(whitelist, *c))
232 {
233 strncat(str, c, 1);
234 }
235 c++;
236 }
237 return str;
238}
239
240#define CMDLINE_SERIALNO "androidboot.serialno="
241#define CMDLINE_SERIALNO_LEN (strlen(CMDLINE_SERIALNO))
242#define CPUINFO_SERIALNO "Serial"
243#define CPUINFO_SERIALNO_LEN (strlen(CPUINFO_SERIALNO))
244#define CPUINFO_HARDWARE "Hardware"
245#define CPUINFO_HARDWARE_LEN (strlen(CPUINFO_HARDWARE))
246
247void get_device_id() {
248 FILE *fp;
249 char line[2048];
250 char hardware_id[32];
251 char* token;
252 char* new_device_id;
253
254 // Assign a blank device_id to start with
255 device_id[0] = 0;
256
257 // First, try the cmdline to see if the serial number was supplied
258 fp = fopen("/proc/cmdline", "rt");
259 if (fp != NULL)
260 {
261 // First step, read the line. For cmdline, it's one long line
262 fgets(line, sizeof(line), fp);
263 fclose(fp);
264
265 // Now, let's tokenize the string
266 token = strtok(line, " ");
267
268 // Let's walk through the line, looking for the CMDLINE_SERIALNO token
269 while (token)
270 {
271 // We don't need to verify the length of token, because if it's too short, it will mismatch CMDLINE_SERIALNO at the NULL
272 if (memcmp(token, CMDLINE_SERIALNO, CMDLINE_SERIALNO_LEN) == 0)
273 {
274 // We found the serial number!
275 strcpy(device_id, token + CMDLINE_SERIALNO_LEN);
276 new_device_id = sanitize_device_id(device_id);
277 strcpy(device_id, new_device_id);
278 free(new_device_id);
279 return;
280 }
281 token = strtok(NULL, " ");
282 }
283 }
284
285 // Now we'll try cpuinfo for a serial number
286 fp = fopen("/proc/cpuinfo", "rt");
287 if (fp != NULL)
288 {
289 while (fgets(line, sizeof(line), fp) != NULL) { // First step, read the line.
290 if (memcmp(line, CPUINFO_SERIALNO, CPUINFO_SERIALNO_LEN) == 0) // check the beginning of the line for "Serial"
291 {
292 // We found the serial number!
293 token = line + CPUINFO_SERIALNO_LEN; // skip past "Serial"
294 while ((*token > 0 && *token <= 32 ) || *token == ':') token++; // skip over all spaces and the colon
295 if (*token != 0) {
296 token[30] = 0;
297 if (token[strlen(token)-1] == 10) { // checking for endline chars and dropping them from the end of the string if needed
298 memset(device_id, 0, sizeof(device_id));
299 strncpy(device_id, token, strlen(token) - 1);
300 } else {
301 strcpy(device_id, token);
302 }
303 LOGI("=> serial from cpuinfo: '%s'\n", device_id);
304 fclose(fp);
305 new_device_id = sanitize_device_id(device_id);
306 strcpy(device_id, new_device_id);
307 free(new_device_id);
308 return;
309 }
310 } else if (memcmp(line, CPUINFO_HARDWARE, CPUINFO_HARDWARE_LEN) == 0) {// We're also going to look for the hardware line in cpuinfo and save it for later in case we don't find the device ID
311 // We found the hardware ID
312 token = line + CPUINFO_HARDWARE_LEN; // skip past "Hardware"
313 while ((*token > 0 && *token <= 32 ) || *token == ':') token++; // skip over all spaces and the colon
314 if (*token != 0) {
315 token[30] = 0;
316 if (token[strlen(token)-1] == 10) { // checking for endline chars and dropping them from the end of the string if needed
317 memset(hardware_id, 0, sizeof(hardware_id));
318 strncpy(hardware_id, token, strlen(token) - 1);
319 } else {
320 strcpy(hardware_id, token);
321 }
322 LOGI("=> hardware id from cpuinfo: '%s'\n", hardware_id);
323 }
324 }
325 }
326 fclose(fp);
327 }
328
329 if (hardware_id[0] != 0) {
330 LOGW("\nusing hardware id for device id: '%s'\n", hardware_id);
331 strcpy(device_id, hardware_id);
332 new_device_id = sanitize_device_id(device_id);
333 strcpy(device_id, new_device_id);
334 free(new_device_id);
335 return;
336 }
337
338 strcpy(device_id, "serialno");
339 LOGE("=> device id not found, using '%s'.", device_id);
340 return;
341}
342
343char* get_path (char* path) {
344 char *s;
345
346 /* Go to the end of the string. */
347 s = path + strlen(path) - 1;
348
349 /* Strip off trailing /s (unless it is also the leading /). */
350 while (path < s && s[0] == '/')
351 s--;
352
353 /* Strip the last component. */
354 while (path <= s && s[0] != '/')
355 s--;
356
357 while (path < s && s[0] == '/')
358 s--;
359
360 if (s < path)
361 return ".";
362
363 s[1] = '\0';
364 return path;
365}
366
367char* basename(char* name) {
368 const char* base;
369 for (base = name; *name; name++)
370 {
371 if(*name == '/')
372 {
373 base = name + 1;
374 }
375 }
376 return (char *) base;
377}
378
379/*
380 Checks md5 for a path
381 Return values:
382 -1 : MD5 does not exist
383 0 : Failed
384 1 : Success
385*/
386int check_md5(char* path) {
387 int o;
388 char cmd[PATH_MAX + 30];
389 char md5file[PATH_MAX + 40];
390 strcpy(md5file, path);
391 strcat(md5file, ".md5");
392 char dirpath[PATH_MAX];
393 char* file;
394 if (access(md5file, F_OK ) != -1) {
395 strcpy(dirpath, md5file);
396 get_path(dirpath);
397 chdir(dirpath);
398 file = basename(md5file);
399 sprintf(cmd, "/sbin/busybox md5sum -c '%s'", file);
400 FILE * cs = __popen(cmd, "r");
401 char cs_s[PATH_MAX + 50];
402 fgets(cs_s, PATH_MAX + 50, cs);
403 char* OK = strstr(cs_s, "OK");
404 if (OK != NULL) {
405 printf("MD5 is good. returning 1\n");
406 o = 1;
407 }
408 else {
409 printf("MD5 is bad. return -2\n");
410 o = -2;
411 }
412
413 __pclose(cs);
414 }
415 else {
416 //No md5 file
417 printf("setting o to -1\n");
418 o = -1;
419 }
420
421 return o;
422}
423
Dees_Troy657c3092012-09-10 20:32:10 -0400424static void set_sdcard_update_bootloader_message() {
425 struct bootloader_message boot;
426 memset(&boot, 0, sizeof(boot));
427 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
428 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
429 set_bootloader_message(&boot);
430}
Dees_Troy7d15c252012-09-05 20:47:21 -0400431
Dees_Troy657c3092012-09-10 20:32:10 -0400432int TWtry_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
433 const ZipEntry* binary_entry =
434 mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
435 if (binary_entry == NULL) {
436 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400437 return INSTALL_CORRUPT;
438 }
Dees_Troy657c3092012-09-10 20:32:10 -0400439 const char* binary = "/tmp/update_binary";
440 unlink(binary);
441 int fd = creat(binary, 0755);
442 if (fd < 0) {
443 mzCloseZipArchive(zip);
444 LOGE("Can't make %s\n", binary);
445 return INSTALL_ERROR;
Dees_Troy7d15c252012-09-05 20:47:21 -0400446 }
Dees_Troy657c3092012-09-10 20:32:10 -0400447 bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
448 close(fd);
449 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400450
Dees_Troy657c3092012-09-10 20:32:10 -0400451 if (!ok) {
452 LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
453 return INSTALL_ERROR;
454 }
Dees_Troy7d15c252012-09-05 20:47:21 -0400455
Dees_Troy657c3092012-09-10 20:32:10 -0400456 int pipefd[2];
457 pipe(pipefd);
Dees_Troy7d15c252012-09-05 20:47:21 -0400458
Dees_Troy657c3092012-09-10 20:32:10 -0400459 // When executing the update binary contained in the package, the
460 // arguments passed are:
461 //
462 // - the version number for this interface
463 //
464 // - an fd to which the program can write in order to update the
465 // progress bar. The program can write single-line commands:
466 //
467 // progress <frac> <secs>
468 // fill up the next <frac> part of of the progress bar
469 // over <secs> seconds. If <secs> is zero, use
470 // set_progress commands to manually control the
471 // progress of this segment of the bar
472 //
473 // set_progress <frac>
474 // <frac> should be between 0.0 and 1.0; sets the
475 // progress bar within the segment defined by the most
476 // recent progress command.
477 //
478 // firmware <"hboot"|"radio"> <filename>
479 // arrange to install the contents of <filename> in the
480 // given partition on reboot.
481 //
482 // (API v2: <filename> may start with "PACKAGE:" to
483 // indicate taking a file from the OTA package.)
484 //
485 // (API v3: this command no longer exists.)
486 //
487 // ui_print <string>
488 // display <string> on the screen.
489 //
490 // - the name of the package zip file.
491 //
492
493 const char** args = (const char**)malloc(sizeof(char*) * 5);
494 args[0] = binary;
495 args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
496 char* temp = (char*)malloc(10);
497 sprintf(temp, "%d", pipefd[1]);
498 args[2] = temp;
499 args[3] = (char*)path;
500 args[4] = NULL;
501
502 pid_t pid = fork();
503 if (pid == 0) {
504 close(pipefd[0]);
505 execv(binary, (char* const*)args);
506 fprintf(stdout, "E:Can't run %s (error)\n", binary);
507 _exit(-1);
508 }
509 close(pipefd[1]);
510 *wipe_cache = 0;
511
512 char buffer[1024];
513 FILE* from_child = fdopen(pipefd[0], "r");
514 LOGI("8\n");
515 while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
516 char* command = strtok(buffer, " \n");
517 if (command == NULL) {
518 continue;
519 } else if (strcmp(command, "progress") == 0) {
520 char* fraction_s = strtok(NULL, " \n");
521 char* seconds_s = strtok(NULL, " \n");
522
523 float fraction = strtof(fraction_s, NULL);
524 int seconds = strtol(seconds_s, NULL, 10);
525
526 //ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
527 } else if (strcmp(command, "set_progress") == 0) {
528 char* fraction_s = strtok(NULL, " \n");
529 float fraction = strtof(fraction_s, NULL);
530 //ui->SetProgress(fraction);
531 } else if (strcmp(command, "ui_print") == 0) {
532 char* str = strtok(NULL, "\n");
533 if (str) {
534 //ui->Print("%s", str);
535 } else {
536 //ui->Print("\n");
537 }
538 } else if (strcmp(command, "wipe_cache") == 0) {
539 *wipe_cache = 1;
540 } else if (strcmp(command, "clear_display") == 0) {
541 //ui->SetBackground(RecoveryUI::NONE);
542 } else {
543 LOGE("unknown command [%s]\n", command);
544 }
545 }
546 fclose(from_child);
547
548 int status;
549 waitpid(pid, &status, 0);
550 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
551 LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
552 return INSTALL_ERROR;
553 }
554 return INSTALL_SUCCESS;
555}
556
557// Look for an RSA signature embedded in the .ZIP file comment given
558// the path to the zip. Verify it matches one of the given public
559// keys.
560//
561// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
562// or no key matches the signature).
563
564int TWverify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) {
565 //ui->SetProgress(0.0);
566
567 FILE* f = fopen(path, "rb");
568 if (f == NULL) {
569 LOGE("failed to open %s (%s)\n", path, strerror(errno));
570 return VERIFY_FAILURE;
571 }
572
573 // An archive with a whole-file signature will end in six bytes:
574 //
575 // (2-byte signature start) $ff $ff (2-byte comment size)
576 //
577 // (As far as the ZIP format is concerned, these are part of the
578 // archive comment.) We start by reading this footer, this tells
579 // us how far back from the end we have to start reading to find
580 // the whole comment.
581
582#define FOOTER_SIZE 6
583
584 if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) {
585 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
586 fclose(f);
587 return VERIFY_FAILURE;
588 }
589
590 unsigned char footer[FOOTER_SIZE];
591 if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) {
592 LOGE("failed to read footer from %s (%s)\n", path, strerror(errno));
593 fclose(f);
594 return VERIFY_FAILURE;
595 }
596
597 if (footer[2] != 0xff || footer[3] != 0xff) {
598 fclose(f);
599 return VERIFY_FAILURE;
600 }
601
602 size_t comment_size = footer[4] + (footer[5] << 8);
603 size_t signature_start = footer[0] + (footer[1] << 8);
604 LOGI("comment is %d bytes; signature %d bytes from end\n",
605 comment_size, signature_start);
606
607 if (signature_start - FOOTER_SIZE < RSANUMBYTES) {
608 // "signature" block isn't big enough to contain an RSA block.
609 LOGE("signature is too short\n");
610 fclose(f);
611 return VERIFY_FAILURE;
612 }
613
614#define EOCD_HEADER_SIZE 22
615
616 // The end-of-central-directory record is 22 bytes plus any
617 // comment length.
618 size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
619
620 if (fseek(f, -eocd_size, SEEK_END) != 0) {
621 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
622 fclose(f);
623 return VERIFY_FAILURE;
624 }
625
626 // Determine how much of the file is covered by the signature.
627 // This is everything except the signature data and length, which
628 // includes all of the EOCD except for the comment length field (2
629 // bytes) and the comment data.
630 size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2;
631
632 unsigned char* eocd = (unsigned char*)malloc(eocd_size);
633 if (eocd == NULL) {
634 LOGE("malloc for EOCD record failed\n");
635 fclose(f);
636 return VERIFY_FAILURE;
637 }
638 if (fread(eocd, 1, eocd_size, f) != eocd_size) {
639 LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno));
640 fclose(f);
641 return VERIFY_FAILURE;
642 }
643
644 // If this is really is the EOCD record, it will begin with the
645 // magic number $50 $4b $05 $06.
646 if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
647 eocd[2] != 0x05 || eocd[3] != 0x06) {
648 LOGE("signature length doesn't match EOCD marker\n");
649 fclose(f);
650 return VERIFY_FAILURE;
651 }
652
653 size_t i;
654 for (i = 4; i < eocd_size-3; ++i) {
655 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
656 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
657 // if the sequence $50 $4b $05 $06 appears anywhere after
658 // the real one, minzip will find the later (wrong) one,
659 // which could be exploitable. Fail verification if
660 // this sequence occurs anywhere after the real one.
661 LOGE("EOCD marker occurs after start of EOCD\n");
662 fclose(f);
663 return VERIFY_FAILURE;
664 }
665 }
666
667#define BUFFER_SIZE 4096
668
669 SHA_CTX ctx;
670 SHA_init(&ctx);
671 unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
672 if (buffer == NULL) {
673 LOGE("failed to alloc memory for sha1 buffer\n");
674 fclose(f);
675 return VERIFY_FAILURE;
676 }
677
678 double frac = -1.0;
679 size_t so_far = 0;
680 fseek(f, 0, SEEK_SET);
681 while (so_far < signed_len) {
682 size_t size = BUFFER_SIZE;
683 if (signed_len - so_far < size) size = signed_len - so_far;
684 if (fread(buffer, 1, size, f) != size) {
685 LOGE("failed to read data from %s (%s)\n", path, strerror(errno));
686 fclose(f);
687 return VERIFY_FAILURE;
688 }
689 SHA_update(&ctx, buffer, size);
690 so_far += size;
691 double f = so_far / (double)signed_len;
692 if (f > frac + 0.02 || size == so_far) {
693 //ui->SetProgress(f);
694 frac = f;
695 }
696 }
697 fclose(f);
698 free(buffer);
699
700 const uint8_t* sha1 = SHA_final(&ctx);
701 for (i = 0; i < numKeys; ++i) {
702 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
703 // the signing tool appends after the signature itself.
704 if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
705 RSANUMBYTES, sha1)) {
706 LOGI("whole-file signature verified against key %d\n", i);
707 free(eocd);
708 return VERIFY_SUCCESS;
709 }
710 }
711 free(eocd);
712 LOGE("failed to verify whole-file signature\n");
713 return VERIFY_FAILURE;
714}
715
716// Reads a file containing one or more public keys as produced by
717// DumpPublicKey: this is an RSAPublicKey struct as it would appear
718// as a C source literal, eg:
719//
720// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
721//
722// (Note that the braces and commas in this example are actual
723// characters the parser expects to find in the file; the ellipses
724// indicate more numbers omitted from this example.)
725//
726// The file may contain multiple keys in this format, separated by
727// commas. The last key must not be followed by a comma.
728//
729// Returns NULL if the file failed to parse, or if it contain zero keys.
730static RSAPublicKey*
731TWload_keys(const char* filename, int* numKeys) {
732 RSAPublicKey* out = NULL;
733 *numKeys = 0;
734
735 FILE* f = fopen(filename, "r");
736 if (f == NULL) {
737 LOGE("opening %s: ERROR\n", filename);
738 goto exit;
739 }
740
741 {
742 int i;
743 bool done = false;
744 while (!done) {
745 ++*numKeys;
746 out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
747 RSAPublicKey* key = out + (*numKeys - 1);
748 if (fscanf(f, " { %i , 0x%x , { %u",
749 &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
750 goto exit;
751 }
752 if (key->len != RSANUMWORDS) {
753 LOGE("key length (%d) does not match expected size\n", key->len);
754 goto exit;
755 }
756 for (i = 1; i < key->len; ++i) {
757 if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
758 }
759 if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
760 for (i = 1; i < key->len; ++i) {
761 if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
762 }
763 fscanf(f, " } } ");
764
765 // if the line ends in a comma, this file has more keys.
766 switch (fgetc(f)) {
767 case ',':
768 // more keys to come.
769 break;
770
771 case EOF:
772 done = true;
773 break;
774
775 default:
776 LOGE("unexpected character between keys\n");
777 goto exit;
778 }
779 }
780 }
781
782 fclose(f);
783 return out;
784
785exit:
786 if (f) fclose(f);
787 free(out);
788 *numKeys = 0;
789 return NULL;
790}
791
792int TWinstall_zip(const char* path, int* wipe_cache) {
793 int err;
794
795 if (DataManager_GetIntValue(TW_SIGNED_ZIP_VERIFY_VAR)) {
796 int numKeys;
797 RSAPublicKey* loadedKeys = TWload_keys(PUBLIC_KEYS_FILE, &numKeys);
798 if (loadedKeys == NULL) {
799 LOGE("Failed to load keys\n");
800 return -1;
801 }
802 LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
803
804 // Give verification half the progress bar...
805 //ui->Print("Verifying update package...\n");
806 //ui->SetProgressType(RecoveryUI::DETERMINATE);
807 //ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
808
809 err = TWverify_file(path, loadedKeys, numKeys);
810 free(loadedKeys);
811 LOGI("verify_file returned %d\n", err);
812 if (err != VERIFY_SUCCESS) {
813 LOGE("signature verification failed\n");
814 return -1;
815 }
816 }
817 /* Try to open the package.
Dees_Troy7d15c252012-09-05 20:47:21 -0400818 */
819 ZipArchive zip;
820 err = mzOpenZipArchive(path, &zip);
821 if (err != 0) {
822 LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
823 return INSTALL_CORRUPT;
824 }
825
826 /* Verify and install the contents of the package.
827 */
Dees_Troy657c3092012-09-10 20:32:10 -0400828 //ui->Print("Installing update...\n");
829 return TWtry_update_binary(path, &zip, wipe_cache);
Dees_Troy51a0e822012-09-05 15:24:24 -0400830}
831
832//partial kangbang from system/vold
833#ifndef CUSTOM_LUN_FILE
834#define CUSTOM_LUN_FILE "/sys/devices/platform/usb_mass_storage/lun%d/file"
835#endif
836
837int usb_storage_enable(void)
838{
839 int fd;
840 char lun_file[255];
841
842 if (DataManager_GetIntValue(TW_HAS_DUAL_STORAGE) == 1 && DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0) {
843 Volume *vol = volume_for_path(DataManager_GetSettingsStoragePath());
844 if (!vol)
845 {
846 LOGE("Unable to locate volume information.");
847 return -1;
848 }
849
850 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
851
852 if ((fd = open(lun_file, O_WRONLY)) < 0)
853 {
854 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
855 return -1;
856 }
857
858 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
859 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
860 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
861 close(fd);
862 return -1;
863 }
864 close(fd);
865
866 Volume *vol2 = volume_for_path(DataManager_GetStrValue(TW_EXTERNAL_PATH));
867 if (!vol)
868 {
869 LOGE("Unable to locate volume information.\n");
870 return -1;
871 }
872
873 sprintf(lun_file, CUSTOM_LUN_FILE, 1);
874
875 if ((fd = open(lun_file, O_WRONLY)) < 0)
876 {
877 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
878 return -1;
879 }
880
881 if ((write(fd, vol2->device, strlen(vol2->device)) < 0) &&
882 (!vol2->device2 || (write(fd, vol2->device, strlen(vol2->device2)) < 0))) {
883 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
884 close(fd);
885 return -1;
886 }
887 close(fd);
888 } else {
889 if (DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0)
890 strcpy(lun_file, DataManager_GetCurrentStoragePath());
891 else
892 strcpy(lun_file, DataManager_GetStrValue(TW_EXTERNAL_PATH));
893
894 Volume *vol = volume_for_path(lun_file);
895 if (!vol)
896 {
897 LOGE("Unable to locate volume information.\n");
898 return -1;
899 }
900
901 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
902
903 if ((fd = open(lun_file, O_WRONLY)) < 0)
904 {
905 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
906 return -1;
907 }
908
909 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
910 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
911 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
912 close(fd);
913 return -1;
914 }
915 close(fd);
916 }
917 return 0;
918}
919
920int usb_storage_disable(void)
921{
922 int fd, index;
923 char lun_file[255];
924
925 for (index=0; index<2; index++) {
926 sprintf(lun_file, CUSTOM_LUN_FILE, index);
927
928 if ((fd = open(lun_file, O_WRONLY)) < 0)
929 {
930 if (index == 0)
931 LOGE("Unable to open ums lunfile '%s': (%s)", lun_file, strerror(errno));
932 return -1;
933 }
934
935 char ch = 0;
936 if (write(fd, &ch, 1) < 0)
937 {
938 if (index == 0)
939 LOGE("Unable to write to ums lunfile '%s': (%s)", lun_file, strerror(errno));
940 close(fd);
941 return -1;
942 }
943
944 close(fd);
945 }
946 return 0;
947}
948
949void wipe_dalvik_cache()
950{
951 //ui_set_background(BACKGROUND_ICON_WIPE);
952 ensure_path_mounted("/data");
953 ensure_path_mounted("/cache");
954 ui_print("\n-- Wiping Dalvik Cache Directories...\n");
955 __system("rm -rf /data/dalvik-cache");
956 ui_print("Cleaned: /data/dalvik-cache...\n");
957 __system("rm -rf /cache/dalvik-cache");
958 ui_print("Cleaned: /cache/dalvik-cache...\n");
959 __system("rm -rf /cache/dc");
960 ui_print("Cleaned: /cache/dc\n");
961
962 struct stat st;
963 LOGE("TODO: Re-implement wipe dalvik into Partition Manager!\n");
964 if (1) //if (0 != stat(sde.blk, &st))
965 {
966 ui_print("/sd-ext not present, skipping\n");
967 } else {
968 __system("mount /sd-ext");
969 LOGI("Mounting /sd-ext\n");
970 if (stat("/sd-ext/dalvik-cache",&st) == 0)
971 {
972 __system("rm -rf /sd-ext/dalvik-cache");
973 ui_print("Cleaned: /sd-ext/dalvik-cache...\n");
974 }
975 }
976 ensure_path_unmounted("/data");
977 ui_print("-- Dalvik Cache Directories Wipe Complete!\n\n");
978 //ui_set_background(BACKGROUND_ICON_MAIN);
979 //if (!ui_text_visible()) return;
980}
981
982// BATTERY STATS
983void wipe_battery_stats()
984{
985 ensure_path_mounted("/data");
986 struct stat st;
987 if (0 != stat("/data/system/batterystats.bin", &st))
988 {
989 ui_print("No Battery Stats Found. No Need To Wipe.\n");
990 } else {
991 //ui_set_background(BACKGROUND_ICON_WIPE);
992 remove("/data/system/batterystats.bin");
993 ui_print("Cleared: Battery Stats...\n");
994 ensure_path_unmounted("/data");
995 }
996}
997
998// ROTATION SETTINGS
999void wipe_rotate_data()
1000{
1001 //ui_set_background(BACKGROUND_ICON_WIPE);
1002 ensure_path_mounted("/data");
1003 __system("rm -r /data/misc/akmd*");
1004 __system("rm -r /data/misc/rild*");
1005 ui_print("Cleared: Rotatation Data...\n");
1006 ensure_path_unmounted("/data");
1007}
1008
1009void fix_perms()
1010{
1011 ensure_path_mounted("/data");
1012 ensure_path_mounted("/system");
1013 //ui_show_progress(1,30);
1014 ui_print("\n-- Fixing Permissions\n");
1015 ui_print("This may take a few minutes.\n");
1016 __system("./sbin/fix_permissions.sh");
1017 ui_print("-- Done.\n\n");
1018 //ui_reset_progress();
1019}
1020
1021int get_battery_level(void)
1022{
1023 static int lastVal = -1;
1024 static time_t nextSecCheck = 0;
1025
1026 struct timeval curTime;
1027 gettimeofday(&curTime, NULL);
1028 if (curTime.tv_sec > nextSecCheck)
1029 {
1030 char cap_s[4];
1031 FILE * cap = fopen("/sys/class/power_supply/battery/capacity","rt");
1032 if (cap)
1033 {
1034 fgets(cap_s, 4, cap);
1035 fclose(cap);
1036 lastVal = atoi(cap_s);
1037 if (lastVal > 100) lastVal = 101;
1038 if (lastVal < 0) lastVal = 0;
1039 }
1040 nextSecCheck = curTime.tv_sec + 60;
1041 }
1042 return lastVal;
1043}
1044
1045char*
1046print_batt_cap() {
1047 char* full_cap_s = (char*)malloc(30);
1048 char full_cap_a[30];
1049
1050 int cap_i = get_battery_level();
1051
1052 //int len = strlen(cap_s);
1053 //if (cap_s[len-1] == '\n') {
1054 // cap_s[len-1] = 0;
1055 //}
1056
1057 // Get a usable time
1058 struct tm *current;
1059 time_t now;
1060 now = time(0);
1061 current = localtime(&now);
1062
1063 sprintf(full_cap_a, "Battery Level: %i%% @ %02D:%02D", cap_i, current->tm_hour, current->tm_min);
1064 strcpy(full_cap_s, full_cap_a);
1065
1066 return full_cap_s;
1067}
1068
1069void update_tz_environment_variables() {
1070 setenv("TZ", DataManager_GetStrValue(TW_TIME_ZONE_VAR), 1);
1071 tzset();
1072}
1073
1074void run_script(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5, const char *str6, const char *str7, int request_confirm)
1075{
1076 ui_print("%s", str1);
1077 //ui_clear_key_queue();
1078 ui_print("\nPress Power to confirm,");
1079 ui_print("\nany other key to abort.\n");
1080 int confirm;
1081 /*if (request_confirm) // this option is used to skip the confirmation when the gui is in use
1082 confirm = ui_wait_key();
1083 else*/
1084 confirm = KEY_POWER;
1085
1086 if (confirm == BTN_MOUSE || confirm == KEY_POWER || confirm == SELECT_ITEM) {
1087 ui_print("%s", str2);
1088 pid_t pid = fork();
1089 if (pid == 0) {
1090 char *args[] = { "/sbin/sh", "-c", (char*)str3, "1>&2", NULL };
1091 execv("/sbin/sh", args);
1092 fprintf(stderr, str4, strerror(errno));
1093 _exit(-1);
1094 }
1095 int status;
1096 while (waitpid(pid, &status, WNOHANG) == 0) {
1097 ui_print(".");
1098 sleep(1);
1099 }
1100 ui_print("\n");
1101 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
1102 ui_print("%s", str5);
1103 } else {
1104 ui_print("%s", str6);
1105 }
1106 } else {
1107 ui_print("%s", str7);
1108 }
1109 //if (!ui_text_visible()) return;
1110}
1111
1112void install_htc_dumlock(void)
1113{
1114 struct statfs fs1, fs2;
1115 int need_libs = 0;
1116
1117 ui_print("Installing HTC Dumlock to system...\n");
1118 ensure_path_mounted("/system");
1119 __system("cp /res/htcd/htcdumlocksys /system/bin/htcdumlock && chmod 755 /system/bin/htcdumlock");
1120 if (statfs("/system/bin/flash_image", &fs1) != 0) {
1121 ui_print("Installing flash_image...\n");
1122 __system("cp /res/htcd/flash_imagesys /system/bin/flash_image && chmod 755 /system/bin/flash_image");
1123 need_libs = 1;
1124 } else
1125 ui_print("flash_image is already installed, skipping...\n");
1126 if (statfs("/system/bin/dump_image", &fs2) != 0) {
1127 ui_print("Installing dump_image...\n");
1128 __system("cp /res/htcd/dump_imagesys /system/bin/dump_image && chmod 755 /system/bin/dump_image");
1129 need_libs = 1;
1130 } else
1131 ui_print("dump_image is already installed, skipping...\n");
1132 if (need_libs) {
1133 ui_print("Installing libs needed for flash_image and dump_image...\n");
1134 __system("cp /res/htcd/libbmlutils.so /system/lib && chmod 755 /system/lib/libbmlutils.so");
1135 __system("cp /res/htcd/libflashutils.so /system/lib && chmod 755 /system/lib/libflashutils.so");
1136 __system("cp /res/htcd/libmmcutils.so /system/lib && chmod 755 /system/lib/libmmcutils.so");
1137 __system("cp /res/htcd/libmtdutils.so /system/lib && chmod 755 /system/lib/libmtdutils.so");
1138 }
1139 ui_print("Installing HTC Dumlock app...\n");
1140 ensure_path_mounted("/data");
1141 mkdir("/data/app", 0777);
1142 __system("rm /data/app/com.teamwin.htcdumlock*");
1143 __system("cp /res/htcd/HTCDumlock.apk /data/app/com.teamwin.htcdumlock.apk");
1144 sync();
1145 ui_print("HTC Dumlock is installed.\n");
1146}
1147
1148void htc_dumlock_restore_original_boot(void)
1149{
1150 ui_print("Restoring original boot...\n");
1151 __system("htcdumlock restore");
1152 ui_print("Original boot restored.\n");
1153}
1154
1155void htc_dumlock_reflash_recovery_to_boot(void)
1156{
1157 ui_print("Reflashing recovery to boot...\n");
1158 __system("htcdumlock recovery noreboot");
1159 ui_print("Recovery is flashed to boot.\n");
1160}
1161
1162void check_and_run_script(const char* script_file, const char* display_name)
1163{
1164 // Check for and run startup script if script exists
1165 struct statfs st;
1166 if (statfs(script_file, &st) == 0) {
1167 ui_print("Running %s script...\n", display_name);
1168 char command[255];
1169 strcpy(command, "chmod 755 ");
1170 strcat(command, script_file);
1171 __system(command);
1172 __system(script_file);
1173 ui_print("\nFinished running %s script.\n", display_name);
1174 }
1175}
1176
1177int check_backup_name(int show_error) {
1178 // Check the backup name to ensure that it is the correct size and contains only valid characters
1179 // and that a backup with that name doesn't already exist
1180 char backup_name[MAX_BACKUP_NAME_LEN];
1181 char backup_loc[255], tw_image_dir[255];
1182 int copy_size = strlen(DataManager_GetStrValue(TW_BACKUP_NAME));
1183 int index, cur_char;
1184 struct statfs st;
1185
1186 // Check size
1187 if (copy_size > MAX_BACKUP_NAME_LEN) {
1188 if (show_error)
1189 LOGE("Backup name is too long.\n");
1190 return -2;
1191 }
1192
1193 // Check characters
1194 strncpy(backup_name, DataManager_GetStrValue(TW_BACKUP_NAME), copy_size);
1195 if (strcmp(backup_name, "0") == 0)
1196 return 0; // A "0" (zero) means to use the current timestamp for the backup name
1197 for (index=0; index<copy_size; index++) {
1198 cur_char = (int)backup_name[index];
1199 if ((cur_char >= 48 && cur_char <= 57) || (cur_char >= 65 && cur_char <= 91) || cur_char == 93 || cur_char == 95 || (cur_char >= 97 && cur_char <= 123) || cur_char == 125 || cur_char == 45 || cur_char == 46) {
1200 // These are valid characters
1201 // Numbers
1202 // Upper case letters
1203 // Lower case letters
1204 // and -_.{}[]
1205 } else {
1206 if (show_error)
1207 LOGE("Backup name '%s' contains invalid character: '%c'\n", backup_name, (char)cur_char);
1208 return -3;
1209 }
1210 }
1211
1212 // Check to make sure that a backup with this name doesn't already exist
1213 strcpy(backup_loc, DataManager_GetStrValue(TW_BACKUPS_FOLDER_VAR));
1214 sprintf(tw_image_dir,"%s/%s/.", backup_loc, backup_name);
1215 if (statfs(tw_image_dir, &st) == 0) {
1216 if (show_error)
1217 LOGE("A backup with this name already exists.\n");
1218 return -4;
1219 }
1220
1221 // No problems found, return 0
1222 return 0;
1223}
Dees_Troy7d15c252012-09-05 20:47:21 -04001224
1225static const char *COMMAND_FILE = "/cache/recovery/command";
1226static const char *INTENT_FILE = "/cache/recovery/intent";
1227static const char *LOG_FILE = "/cache/recovery/log";
1228static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
1229static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
1230static const char *CACHE_ROOT = "/cache";
1231static const char *SDCARD_ROOT = "/sdcard";
1232static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
1233static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
1234
1235// close a file, log an error if the error indicator is set
1236static void check_and_fclose(FILE *fp, const char *name) {
1237 fflush(fp);
1238 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
1239 fclose(fp);
1240}
1241
1242static void copy_log_file(const char* source, const char* destination, int append) {
1243 FILE *log = fopen_path(destination, append ? "a" : "w");
1244 if (log == NULL) {
1245 LOGE("Can't open %s\n", destination);
1246 } else {
1247 FILE *tmplog = fopen(source, "r");
1248 if (tmplog != NULL) {
1249 if (append) {
1250 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
1251 }
1252 char buf[4096];
1253 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
1254 if (append) {
1255 tmplog_offset = ftell(tmplog);
1256 }
1257 check_and_fclose(tmplog, source);
1258 }
1259 check_and_fclose(log, destination);
1260 }
1261}
1262
1263// clear the recovery command and prepare to boot a (hopefully working) system,
1264// copy our log file to cache as well (for the system to read), and
1265// record any intent we were asked to communicate back to the system.
1266// this function is idempotent: call it as many times as you like.
1267void twfinish_recovery(const char *send_intent) {
1268 // By this point, we're ready to return to the main system...
1269 if (send_intent != NULL) {
1270 FILE *fp = fopen_path(INTENT_FILE, "w");
1271 if (fp == NULL) {
1272 LOGE("Can't open %s\n", INTENT_FILE);
1273 } else {
1274 fputs(send_intent, fp);
1275 check_and_fclose(fp, INTENT_FILE);
1276 }
1277 }
1278
1279 // Copy logs to cache so the system can find out what happened.
1280 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
1281 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
1282 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
1283 chmod(LOG_FILE, 0600);
1284 chown(LOG_FILE, 1000, 1000); // system user
1285 chmod(LAST_LOG_FILE, 0640);
1286 chmod(LAST_INSTALL_FILE, 0644);
1287
1288 // Reset to normal system boot so recovery won't cycle indefinitely.
1289 struct bootloader_message boot;
1290 memset(&boot, 0, sizeof(boot));
1291 set_bootloader_message(&boot);
1292
1293 // Remove the command file, so recovery won't repeat indefinitely.
1294 if (ensure_path_mounted(COMMAND_FILE) != 0 ||
1295 (unlink(COMMAND_FILE) && errno != ENOENT)) {
1296 LOGW("Can't unlink %s\n", COMMAND_FILE);
1297 }
1298
1299 ensure_path_unmounted(CACHE_ROOT);
1300 sync(); // For good measure.
1301}
1302