Add appdefined privilege feature
[platform/core/appfw/pkgmgr-info.git] / src / pkgmgrinfo_db.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <ctype.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <grp.h>
10 #include <dirent.h>
11 #include <libgen.h>
12
13 #include <sqlite3.h>
14
15 #include <tzplatform_config.h>
16 #include <db-util.h>
17
18 #include "pkgmgr-info.h"
19 #include "pkgmgrinfo_debug.h"
20 #include "pkgmgrinfo_private.h"
21 #include "pkgmgr_parser.h"
22 #include "pkgmgr_parser_db.h"
23
24 __thread db_handle manifest_db;
25 __thread db_handle cert_db;
26
27 typedef int (*sqlite_query_callback)(void *data, int ncols, char **coltxt, char **colname);
28
29 static int _mkdir_for_user(const char* dir, uid_t uid, gid_t gid)
30 {
31         int ret;
32         char *fullpath;
33         char *subpath;
34         char buf[1024];
35         int fd;
36         struct stat sb;
37
38         fullpath = strdup(dir);
39         if (fullpath == NULL)
40                 return -1;
41         subpath = dirname(fullpath);
42         if (strlen(subpath) > 1 && strcmp(subpath, fullpath) != 0) {
43                 ret = _mkdir_for_user(fullpath, uid, gid);
44                 if (ret == -1) {
45                         free(fullpath);
46                         return ret;
47                 }
48         }
49
50         ret = mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
51         if (ret && errno != EEXIST) {
52                 free(fullpath);
53                 return ret;
54         } else if (ret && errno == EEXIST) {
55                 free(fullpath);
56                 return 0;
57         }
58
59         if (getuid() == ROOT_UID) {
60                 fd = open(dir, O_RDONLY);
61                 if (fd == -1) {
62                         _LOGE("FAIL : open %s : %s", dir,
63                                         strerror_r(errno, buf, sizeof(buf)));
64                         return -1;
65                 }
66                 ret = fstat(fd, &sb);
67                 if (ret == -1) {
68                         _LOGE("FAIL : fstat %s : %s", dir,
69                                         strerror_r(errno, buf, sizeof(buf)));
70                         close(fd);
71                         return -1;
72                 }
73                 if (S_ISLNK(sb.st_mode)) {
74                         _LOGE("FAIL : %s is symlink!", dir);
75                         close(fd);
76                         return -1;
77                 }
78                 ret = fchown(fd, uid, gid);
79                 if (ret == -1) {
80                         _LOGE("FAIL : fchown %s %d.%d, because %s", dir, uid,
81                                         gid, strerror_r(errno, buf, sizeof(buf)));
82                         close(fd);
83                         return -1;
84                 }
85                 close(fd);
86         }
87
88         free(fullpath);
89
90         return 0;
91 }
92
93 static char *_get_db_path(uid_t uid)
94 {
95         const char *db_path;
96         char path[PATH_MAX];
97
98         db_path = tzplatform_getenv(TZ_SYS_DB);
99         if (db_path == NULL) {
100                 _LOGE("Failed to get TZ_SYS_DB path");
101                 return NULL;
102         }
103
104         if (uid == GLOBAL_USER || uid == ROOT_UID)
105                 return strdup(db_path);
106
107         snprintf(path, sizeof(path), "%s/user/%d", db_path, uid);
108
109         return strdup(path);
110 }
111
112 static int __attach_and_create_view(sqlite3 *handle, const char *db, const char *tables[], uid_t uid)
113 {
114         int i;
115         char *err = NULL;
116         char query[MAX_QUERY_LEN];
117
118         if (uid != GLOBAL_USER && uid != ROOT_UID) {
119                 snprintf(query, sizeof(query), "ATTACH DATABASE '%s' AS Global", db);
120                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
121                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
122                         sqlite3_free(err);
123                         return SQLITE_ERROR;
124                 }
125         }
126
127         for (i = 0; tables[i]; i++) {
128                 if (uid != GLOBAL_USER && uid != ROOT_UID)
129                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
130                                         FROM (SELECT *,0 AS for_all_users FROM main.'%s' UNION \
131                                         SELECT *,1 AS for_all_users FROM Global.'%s')",
132                                         tables[i], tables[i], tables[i]);
133                 else
134                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
135                                         FROM (SELECT *,1 AS for_all_users FROM main.'%s')",
136                                         tables[i], tables[i]);
137                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
138                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
139                         sqlite3_free(err);
140                 }
141         }
142
143         return SQLITE_OK;
144 }
145
146 int _check_create_cert_db(void)
147 {
148         return pkgmgr_parser_initialize_cert_db();
149 }
150
151 static gid_t _get_gid(const char *name)
152 {
153         char buf[BUFSIZE];
154         struct group entry;
155         struct group *ge;
156         int ret;
157
158         ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge);
159         if (ret || ge == NULL) {
160                 _LOGE("fail to get gid of %s", name);
161                 return -1;
162         }
163
164         return entry.gr_gid;
165 }
166
167 API const char *getIconPath(uid_t uid, bool readonly)
168 {
169         const char *path = NULL;
170         uid_t uid_caller = getuid();
171         gid_t gid = ROOT_UID;
172
173         if (uid != GLOBAL_USER && uid != ROOT_UID) {
174                 _LOGD("not supported target user");
175                 return NULL;
176         }
177
178         if (readonly)
179                 path = tzplatform_mkpath(TZ_SYS_RO_ICONS, "/");
180
181         /* just allow certain users to create the icon directory if needed. */
182         if (path && (uid_caller == ROOT_UID  ||
183                 uid_caller == APPFW_UID || uid_caller == uid))
184                 _mkdir_for_user(path, uid, gid);
185
186         return path;
187 }
188
189 API char *getUserPkgParserDBPath(void)
190 {
191         return getUserPkgParserDBPathUID(_getuid());
192 }
193
194 API char *getUserPkgParserDBPathUID(uid_t uid)
195 {
196         char pkgmgr_parser_db[PATH_MAX];
197         uid_t uid_caller = getuid();
198         gid_t gid = ROOT_UID;
199         char *db_path;
200
201         db_path = _get_db_path(uid);
202         if (db_path == NULL) {
203                 _LOGE("Failed to get db path %d", uid);
204                 return NULL;
205         }
206         snprintf(pkgmgr_parser_db, sizeof(pkgmgr_parser_db),
207                         "%s/.pkgmgr_parser.db", db_path);
208         if (access(db_path, F_OK) != 0) {
209                 if (uid != GLOBAL_USER && uid != ROOT_UID) {
210                         tzplatform_set_user(uid);
211                         gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
212                         tzplatform_reset_user();
213                 }
214                 /* just allow certain users to create the dbspace directory if needed. */
215                 if (uid_caller == ROOT_UID || uid_caller == APPFW_UID ||
216                                 uid_caller == uid)
217                         _mkdir_for_user(db_path, uid, gid);
218         }
219         free(db_path);
220
221         return strdup(pkgmgr_parser_db);
222 }
223
224 API char *getUserPkgCertDBPath(void)
225 {
226          return getUserPkgCertDBPathUID(_getuid());
227 }
228
229 API char *getUserPkgCertDBPathUID(uid_t uid)
230 {
231         char pkgmgr_cert_db[PATH_MAX];
232         uid_t uid_caller = getuid();
233         gid_t gid = ROOT_UID;
234         char *db_path;
235
236         db_path = _get_db_path(uid);
237         if (db_path == NULL) {
238                 _LOGE("Failed to get db path %d", uid);
239                 return NULL;
240         }
241         snprintf(pkgmgr_cert_db, sizeof(pkgmgr_cert_db),
242                         "%s/.pkgmgr_cert.db", db_path);
243
244         if (uid != GLOBAL_USER && uid != ROOT_UID) {
245                 tzplatform_set_user(uid);
246                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
247                 tzplatform_reset_user();
248         }
249
250         /* just allow certain users to create the dbspace directory if needed. */
251         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
252                 _mkdir_for_user(db_path, uid, gid);
253
254         free(db_path);
255
256         return strdup(pkgmgr_cert_db);
257 }
258
259 API const char *getUserManifestPath(uid_t uid, bool readonly)
260 {
261         const char *path = NULL;
262         uid_t uid_caller = getuid();
263         gid_t gid = ROOT_UID;
264
265         if (uid != GLOBAL_USER && uid != ROOT_UID) {
266                 tzplatform_set_user(uid);
267                 path = tzplatform_mkpath(TZ_USER_PACKAGES, "/");
268                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
269                 tzplatform_reset_user();
270         } else {
271                 if (readonly)
272                         path = tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/");
273                 else
274                         path = tzplatform_mkpath(TZ_SYS_RW_PACKAGES, "/");
275         }
276
277         /* just allow certain users to create the icon directory if needed. */
278         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
279                 _mkdir_for_user(path, uid, gid);
280
281         return path;
282 }
283
284 int __close_manifest_db(void)
285 {
286         if (manifest_db.ref) {
287                 if (--manifest_db.ref == 0)
288                         sqlite3_close(GET_DB(manifest_db));
289                 return 0;
290         }
291         return -1;
292 }
293
294 static const char *parserdb_tables[] = {
295         "package_app_app_category",
296         "package_app_info",
297         "package_app_app_control",
298         "package_app_localized_info",
299         "package_app_app_metadata",
300         "package_info",
301         "package_app_data_control",
302         "package_localized_info",
303         "package_privilege_info",
304         "package_appdefined_privilege_info",
305         "package_app_data_control_privilege",
306         NULL
307 };
308
309 int __open_manifest_db(uid_t uid, bool readonly)
310 {
311         int ret;
312         char *user_pkg_parser;
313         int flags;
314
315         if (manifest_db.ref) {
316                 manifest_db.ref++;
317                 return 0;
318         }
319
320         user_pkg_parser = getUserPkgParserDBPathUID(uid);
321         if (user_pkg_parser == NULL) {
322                 _LOGE("Failed to get pkg parser db path - %d", uid);
323                 return -1;
324         }
325
326         if (access(user_pkg_parser, F_OK) != 0) {
327                 _LOGE("Manifest DB does not exists !!");
328                 free(user_pkg_parser);
329                 return -1;
330         }
331
332         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
333         ret = db_util_open_with_options(user_pkg_parser, &GET_DB(manifest_db),
334                         flags, NULL);
335         if (ret != SQLITE_OK) {
336                 _LOGE("connect db [%s] failed!\n", user_pkg_parser);
337                 free(user_pkg_parser);
338                 return -1;
339         }
340
341         manifest_db.ref++;
342         if (readonly) {
343                 ret = __attach_and_create_view(GET_DB(manifest_db), MANIFEST_DB,
344                                 parserdb_tables, uid);
345                 if (ret != SQLITE_OK) {
346                         _LOGE("attach db [%s] failed!\n", user_pkg_parser);
347                         free(user_pkg_parser);
348                         return -1;
349                 }
350         }
351
352         free(user_pkg_parser);
353
354         return 0;
355 }
356
357 int __close_cert_db(void)
358 {
359         if (cert_db.ref) {
360                 if (--cert_db.ref == 0)
361                         sqlite3_close_v2(GET_DB(cert_db));
362                 return 0;
363         }
364         _LOGE("Certificate DB is already closed !!\n");
365         return -1;
366 }
367
368 static const char *certdb_tables[] = {
369         "package_cert_index_info",
370         "package_cert_info",
371         NULL
372 };
373
374 int __open_cert_db(uid_t uid, bool readonly)
375 {
376         int ret;
377         char *user_cert_parser;
378         int flags;
379
380         if (cert_db.ref) {
381                 cert_db.ref++;
382                 return 0;
383         }
384
385         user_cert_parser = getUserPkgCertDBPathUID(uid);
386         if (user_cert_parser == NULL) {
387                 _LOGE("Failed to get pkg cert db path - %d", uid);
388                 return -1;
389         }
390
391         if (access(user_cert_parser, F_OK) != 0) {
392                 _LOGE("Cert DB does not exists !!");
393                 free(user_cert_parser);
394                 return -1;
395         }
396
397         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
398         ret = db_util_open_with_options(user_cert_parser, &GET_DB(cert_db),
399                         flags, NULL);
400         if (ret != SQLITE_OK) {
401                 _LOGE("connect db [%s] failed!", user_cert_parser);
402                 free(user_cert_parser);
403                 return -1;
404         }
405         cert_db.ref++;
406         if (readonly) {
407                 ret = __attach_and_create_view(GET_DB(cert_db), CERT_DB,
408                                 certdb_tables, uid);
409                 if (ret != SQLITE_OK) {
410                         _LOGE("attach db [%s] failed!", user_cert_parser);
411                         free(user_cert_parser);
412                         return -1;
413                 }
414         }
415
416         free(user_cert_parser);
417
418         return 0;
419 }
420
421 void _save_column_int(sqlite3_stmt *stmt, int idx, int *i)
422 {
423         *i = sqlite3_column_int(stmt, idx);
424 }
425
426 inline void _save_column_str(sqlite3_stmt *stmt, int idx, char **str)
427 {
428         const char *val;
429
430         val = (const char *)sqlite3_column_text(stmt, idx);
431         if (val)
432                 *str = strdup(val);
433 }
434
435 API int pkgmgrinfo_pkginfo_set_usr_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path, uid_t uid)
436 {
437         retvm_if(pkgid == NULL, PMINFO_R_EINVAL, "pkgid is NULL\n");
438         int ret = -1;
439         sqlite3 *pkgmgr_parser_db = NULL;
440         char *query = NULL;
441         char *db_path;
442
443         db_path = getUserPkgParserDBPathUID(uid);
444         if (db_path == NULL) {
445                 _LOGE("Failed to get pkg parser db path - %d", uid);
446                 return PMINFO_R_ERROR;
447         }
448
449         ret = db_util_open_with_options(db_path, &pkgmgr_parser_db,
450                         SQLITE_OPEN_READWRITE, NULL);
451         if (ret != SQLITE_OK) {
452                 _LOGE("connect db failed!");
453                 free(db_path);
454                 return PMINFO_R_ERROR;
455         }
456         free(db_path);
457
458         /*Begin transaction*/
459         /* Setting Manifest DB */
460         ret = sqlite3_exec(pkgmgr_parser_db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
461         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Failed to begin transaction\n");
462         _LOGD("Transaction Begin\n");
463
464         /* pkgcakge_info table */
465         query = sqlite3_mprintf(
466                         "update package_info set installed_storage=%Q, external_path=%Q where package=%Q",
467                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
468
469         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
470         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
471         sqlite3_free(query);
472
473         /* package_app_info table */
474         query = sqlite3_mprintf(
475                         "update package_app_info set app_installed_storage=%Q, app_external_path=%Q where package=%Q",
476                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
477
478         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
479         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
480
481         /*Commit transaction*/
482         ret = sqlite3_exec(pkgmgr_parser_db, "COMMIT", NULL, NULL, NULL);
483         if (ret != SQLITE_OK) {
484                 _LOGE("Failed to commit transaction. Rollback now\n");
485                 ret = sqlite3_exec(pkgmgr_parser_db, "ROLLBACK", NULL, NULL, NULL);
486                 tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
487         }
488         _LOGD("Transaction Commit and End\n");
489
490         ret = PMINFO_R_OK;
491 catch:
492         sqlite3_close(pkgmgr_parser_db);
493         sqlite3_free(query);
494         return ret;
495 }
496
497 API int pkgmgrinfo_pkginfo_set_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path)
498 {
499         return pkgmgrinfo_pkginfo_set_usr_installed_storage(pkgid, location, external_pkg_path, _getuid());
500 }