blob: 16a3f33f20a23f181957fa2eabfca28bf3b3a7f7 [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
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400223int fixPermissions::fixSystemApps() {
224 temp = head;
225 while (temp != NULL) {
226 if (TWFunc::Path_Exists(temp->codePath)) {
227 if (temp->appDir.compare("/system/app") == 0) {
228 if (debug) {
229 LOGI("Looking at '%s'\n", temp->codePath.c_str());
230 LOGI("Fixing permissions on '%s'\n", temp->pkgName.c_str());
231 LOGI("Directory: '%s'\n", temp->appDir.c_str());
232 LOGI("Original package owner: %d, group: %d\n", temp->uid, temp->gid);
233 }
234 if (pchown(temp->codePath, 0, 0) != 0)
235 return -1;
236 if (pchmod(temp->codePath, "0644") != 0)
237 return -1;
238 }
239 } else {
240 //Remove data directory since app isn't installed
241 if (remove_data && TWFunc::Path_Exists(temp->dDir) && temp->appDir.size() >= 9 && temp->appDir.substr(0, 9) != "/mnt/asec") {
242 if (debug)
243 LOGI("Looking at '%s', removing data dir: '%s', appDir: '%s'", temp->codePath.c_str(), temp->dDir.c_str(), temp->appDir.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500244 if (TWFunc::removeDir(temp->dDir, false) != 0) {
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400245 LOGI("Unable to removeDir '%s'\n", temp->dDir.c_str());
246 return -1;
247 }
248 }
249 }
250 temp = temp->next;
251 }
252 return 0;
253}
254
255int fixPermissions::fixDataApps() {
256 bool fix = false;
257 int new_gid = 0;
258 string perms = "0000";
259
260 temp = head;
261 while (temp != NULL) {
262 if (TWFunc::Path_Exists(temp->codePath)) {
263 if (temp->appDir.compare("/data/app") == 0 || temp->appDir.compare("/sd-ext/app") == 0) {
264 fix = true;
265 new_gid = 1000;
266 perms = "0644";
267 } else if (temp->appDir.compare("/data/app-private") == 0 || temp->appDir.compare("/sd-ext/app-private") == 0) {
268 fix = true;
269 new_gid = temp->gid;
270 perms = "0640";
271 } else
272 fix = false;
273 if (fix) {
274 if (debug) {
275 LOGI("Looking at '%s'\n", temp->codePath.c_str());
276 LOGI("Fixing permissions on '%s'\n", temp->pkgName.c_str());
277 LOGI("Directory: '%s'\n", temp->appDir.c_str());
278 LOGI("Original package owner: %d, group: %d\n", temp->uid, temp->gid);
279 }
280 if (pchown(temp->codePath, 1000, new_gid) != 0)
281 return -1;
282 if (pchmod(temp->codePath, perms) != 0)
283 return -1;
284 }
285 } else {
286 //Remove data directory since app isn't installed
287 if (remove_data && TWFunc::Path_Exists(temp->dDir) && temp->appDir.size() >= 9 && temp->appDir.substr(0, 9) != "/mnt/asec") {
288 if (debug)
289 LOGI("Looking at '%s', removing data dir: '%s', appDir: '%s'", temp->codePath.c_str(), temp->dDir.c_str(), temp->appDir.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500290 if (TWFunc::removeDir(temp->dDir, false) != 0) {
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400291 LOGI("Unable to removeDir '%s'\n", temp->dDir.c_str());
292 return -1;
293 }
294 }
295 }
296 temp = temp->next;
297 }
298 return 0;
299}
300
301int fixPermissions::fixAllFiles(string directory, int gid, int uid, string file_perms) {
302 vector <string> files;
303 string file;
304
305 files = listAllFiles(directory);
306 for (unsigned i = 0; i < files.size(); ++i) {
307 file = directory + "/";
308 file.append(files.at(i));
309 if (debug)
310 LOGI("Looking at file '%s'\n", file.c_str());
311 if (pchmod(file, file_perms) != 0)
312 return -1;
313 if (pchown(file, uid, gid) != 0)
314 return -1;
315 }
316 return 0;
317}
318
Dees_Troy201d76b2012-11-16 17:12:02 +0000319int fixPermissions::fixDataData(string dataDir) {
320 string directory, dir;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400321
322 temp = head;
323 while (temp != NULL) {
Dees_Troy201d76b2012-11-16 17:12:02 +0000324 dir = dataDir + temp->dDir;
325 if (TWFunc::Path_Exists(dir)) {
326 vector <string> dataDataDirs = listAllDirectories(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400327 for (unsigned n = 0; n < dataDataDirs.size(); ++n) {
Dees_Troy201d76b2012-11-16 17:12:02 +0000328 directory = dir + "/";
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400329 directory.append(dataDataDirs.at(n));
330 if (debug)
331 LOGI("Looking at data directory: '%s'\n", directory.c_str());
332 if (dataDataDirs.at(n) == ".") {
Dees_Troy201d76b2012-11-16 17:12:02 +0000333 if (pchmod(directory, "0755") != 0)
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400334 return -1;
335 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
336 return -1;
337 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
338 return -1;
339 }
340 else if (dataDataDirs.at(n) == "..") {
341 if (debug)
342 LOGI("Skipping ..\n");
343 continue;
344 }
345 else if (dataDataDirs.at(n) == "lib") {
346 if (pchmod(directory.c_str(), "0755") != 0)
347 return -1;
348 if (pchown(directory.c_str(), 1000, 1000) != 0)
349 return -1;
350 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
351 return -1;
352 }
353 else if (dataDataDirs.at(n) == "shared_prefs") {
354 if (pchmod(directory.c_str(), "0771") != 0)
355 return -1;
356 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
357 return -1;
358 if (fixAllFiles(directory, temp->uid, temp->gid, "0660") != 0)
359 return -1;
360 }
361 else if (dataDataDirs.at(n) == "databases") {
362 if (pchmod(directory.c_str(), "0771") != 0)
363 return -1;
364 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
365 return -1;
366 if (fixAllFiles(directory, temp->uid, temp->gid, "0660") != 0)
367 return -1;
368 }
369 else if (dataDataDirs.at(n) == "cache") {
370 if (pchmod(directory.c_str(), "0771") != 0)
371 return -1;
372 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
373 return -1;
374 if (fixAllFiles(directory, temp->uid, temp->gid, "0600") != 0)
375 return -1;
376 }
377 else {
378 if (pchmod(directory.c_str(), "0771") != 0)
379 return -1;
380 if (pchown(directory.c_str(), temp->uid, temp->gid) != 0)
381 return -1;
382 if (fixAllFiles(directory, temp->uid, temp->gid, "0755") != 0)
383 return -1;
384 }
385 }
386 }
387 temp = temp->next;
388 }
389 return 0;
390}
391
392vector <string> fixPermissions::listAllDirectories(string path) {
393 DIR *dir = opendir(path.c_str());
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400394 vector <string> dirs;
395
396 if (dir == NULL) {
397 LOGE("Error opening '%s'\n", path.c_str());
398 return dirs;
399 }
Dees_Troy201d76b2012-11-16 17:12:02 +0000400 struct dirent *entry = readdir(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400401 while (entry != NULL) {
402 if (entry->d_type == DT_DIR)
403 dirs.push_back(entry->d_name);
404 entry = readdir(dir);
405 }
406 closedir(dir);
407 return dirs;
408}
409
410vector <string> fixPermissions::listAllFiles(string path) {
411 DIR *dir = opendir(path.c_str());
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400412 vector <string> files;
413
414 if (dir == NULL) {
415 LOGE("Error opening '%s'\n", path.c_str());
416 return files;
417 }
Dees_Troy201d76b2012-11-16 17:12:02 +0000418 struct dirent *entry = readdir(dir);
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400419 while (entry != NULL) {
420 if (entry->d_type == DT_REG)
421 files.push_back(entry->d_name);
422 entry = readdir(dir);
423 }
424 closedir(dir);
425 return files;
426}
427
428int fixPermissions::getPackages() {
429 int len = 0;
430 bool skiploop = false;
431 vector <string> skip;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400432 string name;
433 head = NULL;
434
435 skip.push_back("/system/framework/framework-res.apk");
436 skip.push_back("/system/framework/com.htc.resources.apk");
437
438 ifstream xmlFile(packageFile.c_str());
439 xmlFile.seekg(0, ios::end);
440 len = (int) xmlFile.tellg();
441 xmlFile.seekg(0, ios::beg);
442 char xmlBuf[len + 1];
443 xmlFile.read(&xmlBuf[0], len);
444 xmlBuf[len] = '\0';
445 xml_document<> pkgDoc;
446 pkgDoc.parse<parse_full>(&xmlBuf[0]);
447
448 xml_node<> * pkgNode = pkgDoc.first_node("packages");
449 xml_node <> * next = pkgNode->first_node("package");
450
451 if (next == NULL) {
452 LOGE("No packages found to fix.\n");
453 return -1;
454 }
455
456 //Get packages
457 while (next->first_attribute("name") != NULL) {
458 package* temp = new package;
459 for (unsigned n = 0; n < skip.size(); ++n) {
460 if (skip.at(n).compare(next->first_attribute("codePath")->value()) == 0) {
461 skiploop = true;
462 break;
463 }
464 }
465
466 if (skiploop == true) {
467 if (debug)
468 LOGI("Skipping package %s\n", next->first_attribute("codePath")->value());
469 free(temp);
470 next = next->next_sibling();
471 skiploop = false;
472 continue;
473 }
474 name.append((next->first_attribute("name")->value()));
475 temp->pkgName = next->first_attribute("name")->value();
476 if (debug)
477 LOGI("Loading pkg: %s\n", next->first_attribute("name")->value());
Dees_Troy201d76b2012-11-16 17:12:02 +0000478 if (next->first_attribute("codePath") == NULL) {
479 LOGI("Problem with codePath on %s\n", next->first_attribute("name")->value());
480 } else {
481 temp->codePath = next->first_attribute("codePath")->value();
482 temp->app = basename(next->first_attribute("codePath")->value());
483 temp->appDir = dirname(next->first_attribute("codePath")->value());
484 }
485 temp->dDir = name;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400486 if ( next->first_attribute("sharedUserId") != NULL) {
487 temp->uid = atoi(next->first_attribute("sharedUserId")->value());
488 temp->gid = atoi(next->first_attribute("sharedUserId")->value());
489 }
490 else {
Dees_Troy201d76b2012-11-16 17:12:02 +0000491 if (next->first_attribute("userId") == NULL) {
492 LOGI("Problem with userID on %s\n", next->first_attribute("name")->value());
493 } else {
494 temp->uid = atoi(next->first_attribute("userId")->value());
495 temp->gid = atoi(next->first_attribute("userId")->value());
496 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400497 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400498 temp->next = head;
499 head = temp;
Dees_Troy201d76b2012-11-16 17:12:02 +0000500 if (next->next_sibling("package") == NULL)
501 break;
502 name.clear();
503 next = next->next_sibling("package");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400504 }
505 //Get updated packages
506 next = pkgNode->first_node("updated-package");
507 if (next != NULL) {
508 while (next->first_attribute("name") != NULL) {
509 package* temp = new package;
510 for (unsigned n = 0; n < skip.size(); ++n) {
511 if (skip.at(n).compare(next->first_attribute("codePath")->value()) == 0) {
512 skiploop = true;
513 break;
514 }
515 }
516
517 if (skiploop == true) {
518 if (debug)
519 LOGI("Skipping package %s\n", next->first_attribute("codePath")->value());
520 free(temp);
521 next = next->next_sibling();
522 skiploop = false;
523 continue;
524 }
525 name.append((next->first_attribute("name")->value()));
526 temp->pkgName = next->first_attribute("name")->value();
527 if (debug)
528 LOGI("Loading pkg: %s\n", next->first_attribute("name")->value());
Dees_Troy201d76b2012-11-16 17:12:02 +0000529 if (next->first_attribute("codePath") == NULL) {
530 LOGI("Problem with codePath on %s\n", next->first_attribute("name")->value());
531 } else {
532 temp->codePath = next->first_attribute("codePath")->value();
533 temp->app = basename(next->first_attribute("codePath")->value());
534 temp->appDir = dirname(next->first_attribute("codePath")->value());
535 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400536
Dees_Troy201d76b2012-11-16 17:12:02 +0000537 temp->dDir = name;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400538 if ( next->first_attribute("sharedUserId") != NULL) {
539 temp->uid = atoi(next->first_attribute("sharedUserId")->value());
540 temp->gid = atoi(next->first_attribute("sharedUserId")->value());
541 }
542 else {
Dees_Troy201d76b2012-11-16 17:12:02 +0000543 if (next->first_attribute("userId") == NULL) {
544 LOGI("Problem with userID on %s\n", next->first_attribute("name")->value());
545 } else {
546 temp->uid = atoi(next->first_attribute("userId")->value());
547 temp->gid = atoi(next->first_attribute("userId")->value());
548 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400549 }
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400550 temp->next = head;
551 head = temp;
Dees_Troy201d76b2012-11-16 17:12:02 +0000552 if (next->next_sibling("package") == NULL)
553 break;
554 name.clear();
555 next = next->next_sibling("package");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -0400556 }
557 }
558 return 0;
559}