blob: 801e27374924d1dc67223f97226d3b5de3b676ed [file] [log] [blame]
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -04001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <iostream>
20#include <fstream>
21#include <sstream>
22#include <string>
23#include <vector>
24#include <string.h>
25#include <libgen.h>
26#include <unistd.h>
27#include <sys/stat.h>
28#include <dirent.h>
29#include "gui/rapidxml.hpp"
30#include "fixPermissions.hpp"
31#include "twrp-functions.hpp"
32#include "common.h"
33
34using namespace std;
35using namespace rapidxml;
36
37int fixPermissions::fixPerms(bool enable_debug, bool remove_data_for_missing_apps) {
38 packageFile = "/data/system/packages.xml";
39 debug = enable_debug;
40 remove_data = remove_data_for_missing_apps;
Dees_Troy201d76b2012-11-16 17:12:02 +000041 multi_user = TWFunc::Path_Exists("/data/user");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -040042
43 if (!(TWFunc::Path_Exists(packageFile))) {
44 ui_print("Can't check permissions\n");
45 ui_print("after Factory Reset.\n");
46 ui_print("Please boot rom and try\n");
47 ui_print("again after you reboot into\n");
48 ui_print("recovery.\n");
49 return -1;
50 }
51
52 ui_print("Fixing permissions...\nLoading packages...\n");
53 if ((getPackages()) != 0) {
54 return -1;
55 }
56
57 ui_print("Fixing /system/app perissions...\n");
58 if ((fixSystemApps()) != 0) {
59 return -1;
60 }
61
62 ui_print("Fixing /data/app permisions...\n");
63 if ((fixDataApps()) != 0) {
64 return -1;
65 }
66
Dees_Troy201d76b2012-11-16 17:12:02 +000067 if (multi_user) {
68 DIR *d = opendir("/data/user");
69 string new_path, user_id;
70
71 if (d == NULL) {
72 LOGE("Error opening '/data/user'\n");
73 return -1;
74 }
75
76 if (d) {
77 struct dirent *p;
78 while ((p = readdir(d))) {
79 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
80 continue;
81
82 new_path = "/data/user/";
83 new_path.append(p->d_name);
84 user_id = "u";
85 user_id += p->d_name;
86 user_id += "_";
87 if (p->d_type == DT_LNK) {
88 char link[512], realPath[512];
89 strcpy(link, new_path.c_str());
90 memset(realPath, 0, sizeof(realPath));
91 while (readlink(link, realPath, sizeof(realPath)) > 0) {
92 strcpy(link, realPath);
93 memset(realPath, 0, sizeof(realPath));
94 }
95 new_path = link;
96 } else if (p->d_type != DT_DIR) {
97 continue;
98 } else {
99 new_path.append("/");
100 // We're probably going to need to fix permissions on multi user but
101 // it will have to wait for another time. Need to figure out where
102 // the uid and gid is stored for other users.
103 continue;
104 }
105 ui_print("Fixing %s permissions...\n", new_path.c_str());
106 if ((fixDataData(new_path)) != 0) {
107 closedir(d);
108 return -1;
109 }
110 }
111 closedir(d);
112 }
113 } else {
114 ui_print("Fixing /data/data permisions...\n");
115 if ((fixDataData("/data/data/")) != 0) {
116 return -1;
117 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400118 }
119 ui_print("Done fixing permissions.\n");
120 return 0;
121}
122
123int fixPermissions::pchown(string fn, int puid, int pgid) {
124 LOGI("Fixing %s, uid: %d, gid: %d\n", fn.c_str(), puid, pgid);
125 if (chown(fn.c_str(), puid, pgid) != 0) {
126 LOGE("Unable to chown '%s' %i %i\n", fn.c_str(), puid, pgid);
127 return -1;
128 }
129 return 0;
130}
131
132int fixPermissions::pchmod(string fn, string mode) {
133 long mask = 0;
134 LOGI("Fixing %s, mode: %s\n", fn.c_str(), mode.c_str());
135 for ( std::string::size_type n = 0; n < mode.length(); ++n) {
136 if (n == 0) {
137 if (mode[n] == '0')
138 continue;
139 else if (mode[n] == '1')
140 mask = S_ISVTX;
141 else if (mode[n] == '2')
142 mask = S_ISGID;
143 }
144 else if (n == 1) {
145 if (mode[n] == '7') {
146 mask |= S_IRWXU;
147 }
148 if (mode[n] == '6') {
149 mask |= S_IRUSR;
150 mask |= S_IWUSR;
151 }
152 if (mode[n] == '5') {
153 mask |= S_IRUSR;
154 mask |= S_IXUSR;
155 }
156 if (mode[n] == '4')
157 mask |= S_IRUSR;
158 if (mode[n] == '3') {
159 mask |= S_IWUSR;
160 mask |= S_IRUSR;
161 }
162 if (mode[n] == '2')
163 mask |= S_IWUSR;
164 if (mode[n] == '1')
165 mask |= S_IXUSR;
166 }
167 else if (n == 2) {
168 if (mode[n] == '7') {
169 mask |= S_IRWXG;
170 }
171 if (mode[n] == '6') {
172 mask |= S_IRGRP;
173 mask |= S_IWGRP;
174 }
175 if (mode[n] == '5') {
176 mask |= S_IRGRP;
177 mask |= S_IXGRP;
178 }
179 if (mode[n] == '4')
180 mask |= S_IRGRP;
181 if (mode[n] == '3') {
182 mask |= S_IWGRP;
183 mask |= S_IXGRP;
184 }
185 if (mode[n] == '2')
186 mask |= S_IWGRP;
187 if (mode[n] == '1')
188 mask |= S_IXGRP;
189 }
190 else if (n == 3) {
191 if (mode[n] == '7') {
192 mask |= S_IRWXO;
193 }
194 if (mode[n] == '6') {
195 mask |= S_IROTH;
196 mask |= S_IWOTH;
197 }
198 if (mode[n] == '5') {
199 mask |= S_IROTH;
200 mask |= S_IXOTH;
201 }
202 if (mode[n] == '4')
203 mask |= S_IROTH;
204 if (mode[n] == '3') {
205 mask |= S_IWOTH;
206 mask |= S_IXOTH;
207 }
208 if (mode[n] == '2')
Dees_Troy6480ce02012-10-10 10:26:54 -0400209 mask |= S_IWOTH;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400210 if (mode[n] == '1')
Dees_Troy6480ce02012-10-10 10:26:54 -0400211 mask |= S_IXOTH;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400212 }
213 }
214
215 if (chmod(fn.c_str(), mask) != 0) {
216 LOGE("Unable to chmod '%s' %l\n", fn.c_str(), mask);
217 return -1;
218 }
219
220 return 0;
221}
222
223int fixPermissions::removeDir(const string path) {
224 DIR *d = opendir(path.c_str());
225 int r = 0;
226 string new_path;
227
228 if (d == NULL) {
229 LOGE("Error opening '%s'\n", path.c_str());
230 return -1;
231 }
232
233 if (d) {
234 struct dirent *p;
235 while (!r && (p = readdir(d))) {
236 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
237 continue;
238
239 new_path = path + "/";
240 new_path.append(p->d_name);
241 if (p->d_type == DT_DIR) {
242 r = removeDir(new_path);
243 if (!r)
244 LOGI("Unable to removeDir '%s'\n", new_path.c_str());
245 } else {
246 r = unlink(new_path.c_str());
247 if (!r)
248 LOGI("Unable to unlink '%s'\n", new_path.c_str());
249 }
250 }
251 closedir(d);
252 }
253 if (!r)
254 r = rmdir(path.c_str());
255 if (!r)
256 LOGI("Unable to rmdir '%s'\n", path.c_str());
257
258 return r;
259}
260
261int fixPermissions::fixSystemApps() {
262 temp = head;
263 while (temp != NULL) {
264 if (TWFunc::Path_Exists(temp->codePath)) {
265 if (temp->appDir.compare("/system/app") == 0) {
266 if (debug) {
267 LOGI("Looking at '%s'\n", temp->codePath.c_str());
268 LOGI("Fixing permissions on '%s'\n", temp->pkgName.c_str());
269 LOGI("Directory: '%s'\n", temp->appDir.c_str());
270 LOGI("Original package owner: %d, group: %d\n", temp->uid, temp->gid);
271 }
272 if (pchown(temp->codePath, 0, 0) != 0)
273 return -1;
274 if (pchmod(temp->codePath, "0644") != 0)
275 return -1;
276 }
277 } else {
278 //Remove data directory since app isn't installed
279 if (remove_data && TWFunc::Path_Exists(temp->dDir) && temp->appDir.size() >= 9 && temp->appDir.substr(0, 9) != "/mnt/asec") {
280 if (debug)
281 LOGI("Looking at '%s', removing data dir: '%s', appDir: '%s'", temp->codePath.c_str(), temp->dDir.c_str(), temp->appDir.c_str());
282 if (removeDir(temp->dDir) != 0) {
283 LOGI("Unable to removeDir '%s'\n", temp->dDir.c_str());
284 return -1;
285 }
286 }
287 }
288 temp = temp->next;
289 }
290 return 0;
291}
292
293int fixPermissions::fixDataApps() {
294 bool fix = false;
295 int new_gid = 0;
296 string perms = "0000";
297
298 temp = head;
299 while (temp != NULL) {
300 if (TWFunc::Path_Exists(temp->codePath)) {
301 if (temp->appDir.compare("/data/app") == 0 || temp->appDir.compare("/sd-ext/app") == 0) {
302 fix = true;
303 new_gid = 1000;
304 perms = "0644";
305 } else if (temp->appDir.compare("/data/app-private") == 0 || temp->appDir.compare("/sd-ext/app-private") == 0) {
306 fix = true;
307 new_gid = temp->gid;
308 perms = "0640";
309 } else
310 fix = false;
311 if (fix) {
312 if (debug) {
313 LOGI("Looking at '%s'\n", temp->codePath.c_str());
314 LOGI("Fixing permissions on '%s'\n", temp->pkgName.c_str());
315 LOGI("Directory: '%s'\n", temp->appDir.c_str());
316 LOGI("Original package owner: %d, group: %d\n", temp->uid, temp->gid);
317 }
318 if (pchown(temp->codePath, 1000, new_gid) != 0)
319 return -1;
320 if (pchmod(temp->codePath, perms) != 0)
321 return -1;
322 }
323 } else {
324 //Remove data directory since app isn't installed
325 if (remove_data && TWFunc::Path_Exists(temp->dDir) && temp->appDir.size() >= 9 && temp->appDir.substr(0, 9) != "/mnt/asec") {
326 if (debug)
327 LOGI("Looking at '%s', removing data dir: '%s', appDir: '%s'", temp->codePath.c_str(), temp->dDir.c_str(), temp->appDir.c_str());
328 if (removeDir(temp->dDir) != 0) {
329 LOGI("Unable to removeDir '%s'\n", temp->dDir.c_str());
330 return -1;
331 }
332 }
333 }
334 temp = temp->next;
335 }
336 return 0;
337}
338
339int fixPermissions::fixAllFiles(string directory, int gid, int uid, string file_perms) {
340 vector <string> files;
341 string file;
342
343 files = listAllFiles(directory);
344 for (unsigned i = 0; i < files.size(); ++i) {
345 file = directory + "/";
346 file.append(files.at(i));
347 if (debug)
348 LOGI("Looking at file '%s'\n", file.c_str());
349 if (pchmod(file, file_perms) != 0)
350 return -1;
351 if (pchown(file, uid, gid) != 0)
352 return -1;
353 }
354 return 0;
355}
356
Dees_Troy201d76b2012-11-16 17:12:02 +0000357int fixPermissions::fixDataData(string dataDir) {
358 string directory, dir;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400359
360 temp = head;
361 while (temp != NULL) {
Dees_Troy201d76b2012-11-16 17:12:02 +0000362 dir = dataDir + temp->dDir;
363 if (TWFunc::Path_Exists(dir)) {
364 vector <string> dataDataDirs = listAllDirectories(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400365 for (unsigned n = 0; n < dataDataDirs.size(); ++n) {
Dees_Troy201d76b2012-11-16 17:12:02 +0000366 directory = dir + "/";
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400367 directory.append(dataDataDirs.at(n));
368 if (debug)
369 LOGI("Looking at data directory: '%s'\n", directory.c_str());
370 if (dataDataDirs.at(n) == ".") {
Dees_Troy201d76b2012-11-16 17:12:02 +0000371 if (pchmod(directory, "0755") != 0)
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400372 return -1;
373 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
374 return -1;
375 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
376 return -1;
377 }
378 else if (dataDataDirs.at(n) == "..") {
379 if (debug)
380 LOGI("Skipping ..\n");
381 continue;
382 }
383 else if (dataDataDirs.at(n) == "lib") {
384 if (pchmod(directory.c_str(), "0755") != 0)
385 return -1;
386 if (pchown(directory.c_str(), 1000, 1000) != 0)
387 return -1;
388 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
389 return -1;
390 }
391 else if (dataDataDirs.at(n) == "shared_prefs") {
392 if (pchmod(directory.c_str(), "0771") != 0)
393 return -1;
394 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
395 return -1;
396 if (fixAllFiles(directory, temp->uid, temp->gid, "0660") != 0)
397 return -1;
398 }
399 else if (dataDataDirs.at(n) == "databases") {
400 if (pchmod(directory.c_str(), "0771") != 0)
401 return -1;
402 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
403 return -1;
404 if (fixAllFiles(directory, temp->uid, temp->gid, "0660") != 0)
405 return -1;
406 }
407 else if (dataDataDirs.at(n) == "cache") {
408 if (pchmod(directory.c_str(), "0771") != 0)
409 return -1;
410 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
411 return -1;
412 if (fixAllFiles(directory, temp->uid, temp->gid, "0600") != 0)
413 return -1;
414 }
415 else {
416 if (pchmod(directory.c_str(), "0771") != 0)
417 return -1;
418 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
419 return -1;
420 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
421 return -1;
422 }
423 }
424 }
425 temp = temp->next;
426 }
427 return 0;
428}
429
430vector <string> fixPermissions::listAllDirectories(string path) {
431 DIR *dir = opendir(path.c_str());
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400432 vector <string> dirs;
433
434 if (dir == NULL) {
435 LOGE("Error opening '%s'\n", path.c_str());
436 return dirs;
437 }
Dees_Troy201d76b2012-11-16 17:12:02 +0000438 struct dirent *entry = readdir(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400439 while (entry != NULL) {
440 if (entry->d_type == DT_DIR)
441 dirs.push_back(entry->d_name);
442 entry = readdir(dir);
443 }
444 closedir(dir);
445 return dirs;
446}
447
448vector <string> fixPermissions::listAllFiles(string path) {
449 DIR *dir = opendir(path.c_str());
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400450 vector <string> files;
451
452 if (dir == NULL) {
453 LOGE("Error opening '%s'\n", path.c_str());
454 return files;
455 }
Dees_Troy201d76b2012-11-16 17:12:02 +0000456 struct dirent *entry = readdir(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400457 while (entry != NULL) {
458 if (entry->d_type == DT_REG)
459 files.push_back(entry->d_name);
460 entry = readdir(dir);
461 }
462 closedir(dir);
463 return files;
464}
465
466int fixPermissions::getPackages() {
467 int len = 0;
468 bool skiploop = false;
469 vector <string> skip;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400470 string name;
471 head = NULL;
472
473 skip.push_back("/system/framework/framework-res.apk");
474 skip.push_back("/system/framework/com.htc.resources.apk");
475
476 ifstream xmlFile(packageFile.c_str());
477 xmlFile.seekg(0, ios::end);
478 len = (int) xmlFile.tellg();
479 xmlFile.seekg(0, ios::beg);
480 char xmlBuf[len + 1];
481 xmlFile.read(&xmlBuf[0], len);
482 xmlBuf[len] = '\0';
483 xml_document<> pkgDoc;
484 pkgDoc.parse<parse_full>(&xmlBuf[0]);
485
486 xml_node<> * pkgNode = pkgDoc.first_node("packages");
487 xml_node <> * next = pkgNode->first_node("package");
488
489 if (next == NULL) {
490 LOGE("No packages found to fix.\n");
491 return -1;
492 }
493
494 //Get packages
495 while (next->first_attribute("name") != NULL) {
496 package* temp = new package;
497 for (unsigned n = 0; n < skip.size(); ++n) {
498 if (skip.at(n).compare(next->first_attribute("codePath")->value()) == 0) {
499 skiploop = true;
500 break;
501 }
502 }
503
504 if (skiploop == true) {
505 if (debug)
506 LOGI("Skipping package %s\n", next->first_attribute("codePath")->value());
507 free(temp);
508 next = next->next_sibling();
509 skiploop = false;
510 continue;
511 }
512 name.append((next->first_attribute("name")->value()));
513 temp->pkgName = next->first_attribute("name")->value();
514 if (debug)
515 LOGI("Loading pkg: %s\n", next->first_attribute("name")->value());
Dees_Troy201d76b2012-11-16 17:12:02 +0000516 if (next->first_attribute("codePath") == NULL) {
517 LOGI("Problem with codePath on %s\n", next->first_attribute("name")->value());
518 } else {
519 temp->codePath = next->first_attribute("codePath")->value();
520 temp->app = basename(next->first_attribute("codePath")->value());
521 temp->appDir = dirname(next->first_attribute("codePath")->value());
522 }
523 temp->dDir = name;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400524 if ( next->first_attribute("sharedUserId") != NULL) {
525 temp->uid = atoi(next->first_attribute("sharedUserId")->value());
526 temp->gid = atoi(next->first_attribute("sharedUserId")->value());
527 }
528 else {
Dees_Troy201d76b2012-11-16 17:12:02 +0000529 if (next->first_attribute("userId") == NULL) {
530 LOGI("Problem with userID on %s\n", next->first_attribute("name")->value());
531 } else {
532 temp->uid = atoi(next->first_attribute("userId")->value());
533 temp->gid = atoi(next->first_attribute("userId")->value());
534 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400535 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400536 temp->next = head;
537 head = temp;
Dees_Troy201d76b2012-11-16 17:12:02 +0000538 if (next->next_sibling("package") == NULL)
539 break;
540 name.clear();
541 next = next->next_sibling("package");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400542 }
543 //Get updated packages
544 next = pkgNode->first_node("updated-package");
545 if (next != NULL) {
546 while (next->first_attribute("name") != NULL) {
547 package* temp = new package;
548 for (unsigned n = 0; n < skip.size(); ++n) {
549 if (skip.at(n).compare(next->first_attribute("codePath")->value()) == 0) {
550 skiploop = true;
551 break;
552 }
553 }
554
555 if (skiploop == true) {
556 if (debug)
557 LOGI("Skipping package %s\n", next->first_attribute("codePath")->value());
558 free(temp);
559 next = next->next_sibling();
560 skiploop = false;
561 continue;
562 }
563 name.append((next->first_attribute("name")->value()));
564 temp->pkgName = next->first_attribute("name")->value();
565 if (debug)
566 LOGI("Loading pkg: %s\n", next->first_attribute("name")->value());
Dees_Troy201d76b2012-11-16 17:12:02 +0000567 if (next->first_attribute("codePath") == NULL) {
568 LOGI("Problem with codePath on %s\n", next->first_attribute("name")->value());
569 } else {
570 temp->codePath = next->first_attribute("codePath")->value();
571 temp->app = basename(next->first_attribute("codePath")->value());
572 temp->appDir = dirname(next->first_attribute("codePath")->value());
573 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400574
Dees_Troy201d76b2012-11-16 17:12:02 +0000575 temp->dDir = name;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400576 if ( next->first_attribute("sharedUserId") != NULL) {
577 temp->uid = atoi(next->first_attribute("sharedUserId")->value());
578 temp->gid = atoi(next->first_attribute("sharedUserId")->value());
579 }
580 else {
Dees_Troy201d76b2012-11-16 17:12:02 +0000581 if (next->first_attribute("userId") == NULL) {
582 LOGI("Problem with userID on %s\n", next->first_attribute("name")->value());
583 } else {
584 temp->uid = atoi(next->first_attribute("userId")->value());
585 temp->gid = atoi(next->first_attribute("userId")->value());
586 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400587 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400588 temp->next = head;
589 head = temp;
Dees_Troy201d76b2012-11-16 17:12:02 +0000590 if (next->next_sibling("package") == NULL)
591 break;
592 name.clear();
593 next = next->next_sibling("package");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400594 }
595 }
596 return 0;
597}