--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Junghyun Yeon <jungh.yeon@samsung.com>,
+ * Sangyoon Jang <s89.jang@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <tzplatform_config.h>
+
+#include "pkgmgr-info.h"
+#include "pkgmgr_parser_db.h"
+
+#ifndef OWNER_ROOT
+#define OWNER_ROOT 0
+#endif
+#ifndef GLOBAL_USER
+#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
+#endif
+
+static int _remove_file(const char *path)
+{
+ if (!path)
+ return 0;
+
+ if (access(path, F_OK) != 0)
+ return 0;
+
+ return remove(path);
+}
+
+static int _remove_db(uid_t uid)
+{
+ char *cert_db;
+ char *parser_db;
+ char journal_path[PATH_MAX];
+
+ parser_db = getUserPkgParserDBPathUID(uid);
+ if (!parser_db) {
+ printf("Failed to get parser db path\n");
+ return -1;
+ }
+
+ if (_remove_file(parser_db) != 0) {
+ printf("Failed to remove parser db[%s]\n", parser_db);
+ free(parser_db);
+ return -1;
+ }
+
+ snprintf(journal_path, sizeof(journal_path), "%s-journal", parser_db);
+ free(parser_db);
+ if (_remove_file(journal_path) != 0) {
+ printf("Failed to remove journal[%s]\n", journal_path);
+ return -1;
+ }
+
+ if (uid != OWNER_ROOT && uid != GLOBAL_USER)
+ return 0;
+
+ cert_db = getUserPkgCertDBPath();
+ if (!cert_db) {
+ printf("Failed to get cet db path\n");
+ return -1;
+ }
+
+ if (_remove_file(cert_db) != 0) {
+ printf("Failed to remove parser db[%s]\n", cert_db);
+ free(cert_db);
+ return -1;
+ }
+
+ snprintf(journal_path, sizeof(journal_path), "%s-journal", cert_db);
+ free(cert_db);
+ if (_remove_file(journal_path) != 0) {
+ printf("Failed to remove journal[%s]\n", journal_path);
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int uid;
+ int ret = 0;
+
+ if ((int)getuid() > OWNER_ROOT) {
+ printf("This cmd is not allowed for regular user\n");
+ return -1;
+ }
+
+ if (argc == 1) {
+ printf("argument should be provided\n");
+ return -1;
+ }
+
+ uid = atoi(argv[1]);
+ ret = _remove_db((uid_t)uid);
+ if (ret != 0)
+ printf("failed to remove database for uid[%d]\n", uid);
+
+ ret = pkgmgr_parser_initialize_parser_db((uid_t)uid);
+ if (ret != 0) {
+ printf("failed to create parser db for uid [%d], err[%d]\n", uid, ret);
+ return -1;
+
+ }
+
+ if (uid == 0) {
+ ret = pkgmgr_parser_initialize_cert_db();
+ if (ret != 0) {
+ printf("failed to create cert db for uid [%d], err[%d]\n", uid, ret);
+ return -1;
+ }
+ }
+
+ return 0;
+}
#define _GNU_SOURCE
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <unistd.h>
#include <sqlite3.h>
#include <tzplatform_config.h>
+#include <pkgmgr_parser_db.h>
+
+#ifndef APPFW_USER
+#define APPFW_USER "app_fw"
+#endif
+#ifndef OWNER_ROOT
+#define OWNER_ROOT 0
+#endif
#define REGULAR_USER 5000
#define MAX_QUERY_LEN 4096
+#define BUFSIZE 4096
#define PKGMGR_PARSER_DB_FILE tzplatform_mkpath(TZ_SYS_DB, ".pkgmgr_parser.db")
#define PKGMGR_CERT_DB_FILE tzplatform_mkpath(TZ_SYS_DB, ".pkgmgr_cert.db")
-static int __rollback_db(sqlite3 *db, const char *table_name)
+typedef struct user_info {
+ uid_t uid;
+ char *db_path;
+} user_info;
+
+static GList *user_info_list;
+
+static char *__get_dbpath(uid_t uid)
{
- static const char rollback_query_raw[] =
- "SELECT COUNT(*) FROM %s WHERE 1=0";
- int ret;
- sqlite3_stmt *stmt = NULL;
- char query[MAX_QUERY_LEN] = { '\0' };
+ const char *db_path;
+ char path[PATH_MAX];
- sqlite3_snprintf(MAX_QUERY_LEN, query, rollback_query_raw, table_name);
- ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
- if (ret != SQLITE_OK) {
- printf("Failed to recover db : %s\n", sqlite3_errmsg(db));
- return -1;
+ db_path = tzplatform_getenv(TZ_SYS_DB);
+ if (db_path == NULL) {
+ printf("Failed to get TZ_SYS_DB path");
+ return NULL;
}
- sqlite3_finalize(stmt);
- return 0;
+
+ snprintf(path, sizeof(path), "%s/user/%d/.pkgmgr_parser.db", db_path, uid);
+ return strdup(path);
}
-static int __check_and_rollback_db(const char *db_path, const char *table_name)
+static bool __integrity_check(const char *db_path)
{
int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ const char *check_result;
+ static const char integrity_check_query[] =
+ "PRAGMA integrity_check";
sqlite3 *db;
ret = sqlite3_open_v2(db_path, &db,
SQLITE_OPEN_READWRITE, NULL);
if (ret != SQLITE_OK) {
printf("Failed to open db\n");
- return -1;
+ return false;
+ }
+
+ ret = sqlite3_prepare_v2(db, integrity_check_query,
+ strlen(integrity_check_query), &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ printf("Failed to check integrity_check : %s\n", sqlite3_errmsg(db));
+ goto err;
}
- ret = __rollback_db(db, table_name);
- if (ret != 0)
- printf("Failed to rollback db\n");
+ ret = sqlite3_step(stmt);
+ if (ret != SQLITE_ROW) {
+ printf("Failed to check integrity db :%s\n", sqlite3_errmsg(db));
+ goto err;
+ }
+
+ check_result = (const char *)sqlite3_column_text(stmt, 0);
+ if (!check_result) {
+ printf("Failed to check integrity db :%s\n", sqlite3_errmsg(db));
+ goto err;
+ }
+
+ if (strcasecmp(check_result, "ok") != 0) {
+ printf("db corrupted :%s\n", db_path);
+ goto err;
+ }
+ sqlite3_finalize(stmt);
+ sqlite3_close(db);
+ return true;
+
+err:
+ sqlite3_finalize(stmt);
sqlite3_close(db);
- return ret;
+ return false;
}
-static void _check_db()
+static bool __change_owner(const char *files[2], uid_t uid)
{
int ret;
+ int i;
+ int fd;
+ struct passwd pwd;
+ struct passwd *result;
+ char buf[BUFSIZE];
+ struct stat sb;
+ mode_t mode;
+
+ if (uid == OWNER_ROOT) {
+ ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result);
+ if (result == NULL) {
+ if (ret == 0)
+ printf("no such user: %d\n", uid);
+ else
+ printf("getpwnam_r failed: %d", errno);
+ return false;
+ }
+ uid = pwd.pw_uid;
+ }
+
+ ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+ if (result == NULL) {
+ if (ret == 0)
+ printf("no such user: %d\n", uid);
+ else
+ printf("getpwuid_r failed: %d\n", errno);
+ return false;
+ }
+
+ for (i = 0; i < 2; i++) {
+ fd = open(files[i], O_RDONLY);
+ if (fd == -1) {
+ printf("open %s failed: %d\n", files[i], errno);
+ return false;
+ }
+ ret = fstat(fd, &sb);
+ if (ret == -1) {
+ printf("stat %s failed: %d\n", files[i], errno);
+ close(fd);
+ return false;
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ printf("%s is symlink!\n", files[i]);
+ close(fd);
+ return false;
+ }
+ ret = fchown(fd, uid, pwd.pw_gid);
+ if (ret == -1) {
+ printf("fchown %s failed: %d\n", files[i], errno);
+ close(fd);
+ return false;
+ }
+
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ if (strstr(files[0], PKGMGR_CERT_DB_FILE) != NULL)
+ mode |= S_IWOTH;
+ ret = fchmod(fd, mode);
+ if (ret == -1) {
+ printf("fchmod %s failed: %d\n", files[i], errno);
+ close(fd);
+ return false;;
+ }
+ close(fd);
+ }
+
+ return true;
+}
+
+static void __change_permission(uid_t uid)
+{
+ const char *files[2];
+ char *parser_dbpath = NULL;
+ char journal_file[PATH_MAX];
+ GList *tmp_list;
+ user_info *tmp_info;
+
+ if (uid < REGULAR_USER) {
+ files[0] = PKGMGR_PARSER_DB_FILE;
+ snprintf(journal_file, sizeof(journal_file),
+ "%s-journal", PKGMGR_PARSER_DB_FILE);
+ files[1] = journal_file;
+
+ if (!__change_owner(files, uid)) {
+ printf("Failed to change ownership\n");
+ return;
+ }
+
+ files[0] = PKGMGR_CERT_DB_FILE;
+ snprintf(journal_file, sizeof(journal_file),
+ "%s-journal", PKGMGR_CERT_DB_FILE);
+ files[1] = journal_file;
+ if (!__change_owner(files, uid)) {
+ printf("Failed to change ownership\n");
+ return;
+ }
+ } else {
+ for (tmp_list = user_info_list; tmp_list != NULL;
+ tmp_list = g_list_next(tmp_list)) {
+ tmp_info = (user_info *)tmp_list->data;
+ if (!tmp_info)
+ continue;
+
+ if (tmp_info->uid == uid) {
+ parser_dbpath = tmp_info->db_path;
+ break;
+ }
+ }
+ files[0] = parser_dbpath;
+ snprintf(journal_file, sizeof(journal_file),
+ "%s-journal", parser_dbpath);
+ files[1] = journal_file;
+
+ if (!__change_owner(files, uid)) {
+ printf("Failed to change ownership\n");
+ return;
+ }
+ }
+}
+
+static void _xsystem(const char *argv[])
+{
+ int status = 0;
+ pid_t pid;
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ perror("fork failed");
+ return;
+ case 0:
+ /* child */
+ execvp(argv[0], (char *const *)argv);
+ _exit(-1);
+ default:
+ /* parent */
+ break;
+ }
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid failed");
+ return;
+ }
+ if (WIFSIGNALED(status)) {
+ perror("signal");
+ return;
+ }
+ if (!WIFEXITED(status)) {
+ /* shouldn't happen */
+ perror("should not happen");
+ return;
+ }
+}
+
+static void __create_db(uid_t uid)
+{
+ char uid_string[11];
+ const char *create_db[] = { "/usr/bin/pkg-db-creator", uid_string, NULL};
+
+ snprintf(uid_string, sizeof(uid_string), "%d", (int)uid);
+ _xsystem(create_db);
+}
- ret = __check_and_rollback_db(PKGMGR_PARSER_DB_FILE, "package_info");
- if (ret != 0)
- printf("Failed to check and rollback parser db\n");
+static void __initdb(uid_t uid)
+{
+ char uid_string[11];
+ const char *initdb_rw[] = { "/usr/bin/pkg_initdb",
+ "--recover-db", "--uid", uid_string, "--keep-db", NULL};
+ const char *initdb_ro[] = { "/usr/bin/pkg_initdb",
+ "--recover-db", "--keep-db", NULL};
- ret = __check_and_rollback_db(PKGMGR_CERT_DB_FILE, "package_cert_info");
- if (ret != 0)
- printf("Failed to check and rollback cert db\n");
+ __create_db(uid);
+ __change_permission(uid);
+ snprintf(uid_string, sizeof(uid_string), "%d", (int)uid);
+ _xsystem((uid > REGULAR_USER) ? initdb_rw : initdb_ro);
}
+static void __initdb_all()
+{
+ GList *tmp_list = NULL;
+ user_info *tmp_info;
+ __initdb(getuid());
+
+ for (tmp_list = user_info_list;
+ tmp_list != NULL; tmp_list = g_list_next(tmp_list)) {
+ tmp_info = (user_info *)tmp_list->data;
+ if (!tmp_info || tmp_info->uid < REGULAR_USER)
+ continue;
+ __initdb(tmp_info->uid);
+ }
+}
+
+static void __check_user_db()
+{
+ GList *tmp_list = NULL;
+ user_info *tmp_info;
+
+ for (tmp_list = user_info_list;
+ tmp_list != NULL; tmp_list = g_list_next(tmp_list)) {
+ tmp_info = (user_info *)tmp_list->data;
+ if (!tmp_info)
+ continue;
+ if (!__integrity_check(tmp_info->db_path)) {
+ printf("User db for %d has corrupted\n", (int)tmp_info->uid);
+ __initdb(tmp_info->uid);
+ }
+ }
+}
+
+static void _free_user_info(gpointer data)
+{
+ user_info *info = (user_info *)data;
+ free(info->db_path);
+ free(info);
+}
+
+static void _get_user_list()
+{
+ DIR *dir;
+ struct dirent *ent;
+ struct stat stats;
+ char traverse_path[PATH_MAX];
+ char abs_dirname[PATH_MAX];
+ const char *db_path;
+ uid_t uid;
+ user_info *info;
+
+ db_path = tzplatform_getenv(TZ_SYS_DB);
+ if (db_path == NULL) {
+ printf("Failed to get TZ_SYS_DB path");
+ return;
+ }
+
+ snprintf(traverse_path, sizeof(traverse_path), "%s/user", db_path);
+ dir = opendir(traverse_path);
+
+ while ((ent = readdir(dir)) != NULL) {
+ snprintf(abs_dirname, PATH_MAX, "%s/%s", traverse_path,
+ ent->d_name);
+ stat(abs_dirname, &stats);
+ if (!strcmp(".", ent->d_name) || !strcmp("..", ent->d_name) ||
+ !S_ISDIR(stats.st_mode))
+ continue;
+ info = calloc(1, sizeof(user_info));
+ if (!info) {
+ closedir(dir);
+ return;
+ }
+
+ uid = (uid_t)atoi(ent->d_name);
+ if (!uid) {
+ free(info);
+ continue;
+ }
+ info->uid = uid;
+ info->db_path = __get_dbpath(uid);
+ user_info_list = g_list_append(user_info_list, info);
+ }
+
+ closedir(dir);
+}
+
+static void _check_db()
+{
+ if (!__integrity_check(PKGMGR_CERT_DB_FILE)) {
+ printf("Cert db corrupted. restore entire pkgmgr db\n");
+ __initdb_all();
+ return;
+ } else if (!__integrity_check(PKGMGR_PARSER_DB_FILE)) {
+ printf("Global parser db corrupted. restore entire pkgmgr db\n");
+ __initdb_all();
+ return;
+ }
+
+ __check_user_db();
+}
int main(int argc, char *argv[])
{
return -1;
}
+ _get_user_list();
_check_db();
+ g_list_free_full(user_info_list, _free_user_info);
return 0;
}