Release version 0.22.40
[platform/core/appfw/pkgmgr-info.git] / src / server / initialize_db_internal.c
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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 #define _GNU_SOURCE
18
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/smack.h>
24 #include <pwd.h>
25
26 #include <gio/gio.h>
27 #include <sqlite3.h>
28
29 #include <pkgmgr_parser_db_queries.h>
30 #include <system_info.h>
31
32 #include "pkgmgrinfo_internal.h"
33 #include "pkgmgrinfo_private.h"
34 #include "pkgmgrinfo_debug.h"
35
36
37 #ifndef OWNER_ROOT
38 #define OWNER_ROOT 0
39 #endif
40 #ifndef APPFW_USER
41 #define APPFW_USER "app_fw"
42 #endif
43
44 /* TODO: Do not labeling directly */
45 #define DB_LABEL "User::Home"
46 #define SET_SMACK_LABEL(x)                                                     \
47 do {                                                                           \
48         if (smack_setlabel((x), DB_LABEL, SMACK_LABEL_ACCESS))                 \
49                 _LOGE("failed chsmack -a %s %s", DB_LABEL, x);                 \
50         else                                                                   \
51                 _LOGD("chsmack -a %s %s", DB_LABEL, x);                        \
52 } while (0)
53
54 #define DB_VERSION_PATH SYSCONFDIR "/package-manager/pkg_db_version.txt"
55
56 static const char *__get_cert_db_path(void)
57 {
58         return tzplatform_mkpath(TZ_SYS_DB, ".pkgmgr_cert.db");
59 }
60
61 static int __set_db_permission(const char *path, uid_t uid)
62 {
63         int fd;
64         const char *files[2];
65         char journal_file[BUFSIZE];
66         struct stat sb;
67         mode_t mode;
68         struct passwd pwd;
69         struct passwd *result;
70         char buf[BUFSIZE];
71         int ret;
72         int i;
73
74         if (getuid() != OWNER_ROOT)
75                 return 0;
76
77         if (uid == OWNER_ROOT || uid == GLOBAL_USER) {
78                 ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result);
79                 if (result == NULL) {
80                         if (ret == 0)
81                                 _LOGE("no such user: %d", uid);
82                         else
83                                 _LOGE("getpwuid_r failed: %d", errno);
84                         return -1;
85                 }
86                 uid = pwd.pw_uid;
87         }
88
89         snprintf(journal_file, sizeof(journal_file), "%s-journal", path);
90         files[0] = path;
91         files[1] = journal_file;
92
93         ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
94         if (result == NULL) {
95                 if (ret == 0)
96                         _LOGE("no such user: %d", uid);
97                 else
98                         _LOGE("getpwuid_r failed: %d", errno);
99                 return -1;
100         }
101
102         for (i = 0; i < 2; i++) {
103                 fd = open(files[i], O_RDONLY);
104                 if (fd == -1) {
105                         _LOGE("open %s failed: %d", files[i], errno);
106                         return -1;
107                 }
108                 ret = fstat(fd, &sb);
109                 if (ret == -1) {
110                         _LOGE("stat %s failed: %d", files[i], errno);
111                         close(fd);
112                         return -1;
113                 }
114                 if (S_ISLNK(sb.st_mode)) {
115                         _LOGE("%s is symlink!", files[i]);
116                         close(fd);
117                         return -1;
118                 }
119                 ret = fchown(fd, uid, pwd.pw_gid);
120                 if (ret == -1) {
121                         _LOGE("fchown %s failed: %d", files[i], errno);
122                         close(fd);
123                         return -1;
124                 }
125
126                 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
127                 if (!strcmp(path, __get_cert_db_path()))
128                         mode |= S_IWOTH;
129                 ret = fchmod(fd, mode);
130                 if (ret == -1) {
131                         _LOGD("fchmod %s failed: %d", files[i], errno);
132                         close(fd);
133                         return -1;
134                 }
135                 close(fd);
136                 SET_SMACK_LABEL(files[i]);
137         }
138
139         return 0;
140 }
141
142 static int __set_db_version(sqlite3 *db) {
143         static const char query_raw[] = "PRAGMA user_version=%Q";
144         int ret;
145         FILE *fp = NULL;
146         sqlite3_stmt *stmt;
147         char version[PKG_STRING_LEN_MAX] = { 0 };
148         char *query = NULL;
149
150         fp = fopen(DB_VERSION_PATH, "r");
151         if (fp == NULL) {
152                 _LOGE("Failed to open db version file");
153                 return -1;
154         }
155
156         if (fgets(version, sizeof(version), fp) == NULL) {
157                 _LOGE("Failed to get version information");
158                 fclose(fp);
159                 return -1;
160         }
161         fclose(fp);
162
163         query = sqlite3_mprintf(query_raw, version);
164         if (!query) {
165                 _LOGE("Out of memory");
166                 return -1;
167         }
168
169         ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
170         sqlite3_free(query);
171         if (ret != SQLITE_OK) {
172                 _LOGE("prepare failed: %s", sqlite3_errmsg(db));
173                 return -1;
174         }
175
176         ret = sqlite3_step(stmt);
177         if (ret != SQLITE_DONE) {
178                 _LOGE("sqlite3_step failed: %d", ret);
179                 sqlite3_finalize(stmt);
180                 return -1;
181         }
182
183         sqlite3_finalize(stmt);
184
185         return 0;
186 }
187
188 static int __create_tables(sqlite3 *db, const char **queries)
189 {
190         int ret;
191         int i;
192         for (i = 0; queries[i] != NULL; i++) {
193                 ret = sqlite3_exec(db, queries[i], NULL, NULL, NULL);
194                 if (ret != SQLITE_OK) {
195                         _LOGE("exec failed: %s", sqlite3_errmsg(db));
196                         return -1;
197                 }
198         }
199         return 0;
200 }
201
202 static int __initialize_db(sqlite3 *db, const char *dbpath, uid_t uid)
203 {
204         const char **queries;
205
206         if (__set_db_version(db))
207                 return -1;
208
209         if (strstr(dbpath, ".pkgmgr_parser.db")) {
210                 queries = PARSER_INIT_QUERIES;
211         } else if (strstr(dbpath, ".pkgmgr_cert.db")) {
212                 queries = CERT_INIT_QUERIES;
213         } else {
214                 _LOGE("unexpected dbpath: %s", dbpath);
215                 return -1;
216         }
217
218         __BEGIN_TRANSACTION(db);
219         __DO_TRANSACTION(db, __create_tables(db, queries));
220         __END_TRANSACTION(db);
221
222         if (__set_db_permission(dbpath, uid))
223                 _LOGE("failed to set db permission");
224
225         return 0;
226 }
227
228 API int pkgmgr_parser_internal_initialize_db(sqlite3 *db, uid_t uid)
229 {
230         const char *dbpath;
231
232         dbpath = sqlite3_db_filename(db, "main");
233         if (dbpath == NULL) {
234                 _LOGE("Fail to get db filename");
235                 return -1;
236         }
237
238         return __initialize_db(db, dbpath, uid);
239 }