7af6e7123271256d39b3c56beea761db43a9f3f0
[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
23 #define QUERY_CREATE_TABLE_PACKAGE_CERT_INDEX_INFO \
24         "CREATE TABLE IF NOT EXISTS package_cert_index_info( " \
25         " cert_info TEXT UNIQUE, " \
26         " cert_id INTEGER PRIMARY KEY, " \
27         " cert_ref_count INTEGER NOT NULL)"
28
29 #define QUERY_CREATE_TABLE_PACKAGE_CERT_INFO \
30         "CREATE TABLE IF NOT EXISTS package_cert_info( " \
31         " package TEXT PRIMARY KEY, " \
32         " package_count INTEGER, " \
33         " author_root_cert INTEGER, " \
34         " author_im_cert INTEGER, " \
35         " author_signer_cert INTEGER, " \
36         " dist_root_cert INTEGER, " \
37         " dist_im_cert INTEGER, " \
38         " dist_signer_cert INTEGER, " \
39         " dist2_root_cert INTEGER, " \
40         " dist2_im_cert INTEGER, " \
41         " dist2_signer_cert INTEGER)"
42
43 #define QUERY_CREATE_TRIGGER_UPDATE_CERT_INFO \
44         "CREATE TRIGGER IF NOT EXISTS update_cert_info " \
45         "AFTER UPDATE ON package_cert_info " \
46         "WHEN (NEW.package_count = 0) " \
47         "BEGIN" \
48         " DELETE FROM package_cert_info WHERE package=OLD.package;" \
49         "END;"
50
51 #define QUERY_CREATE_TRIGGER_UPDATE_CERT_INFO2 \
52         "CREATE TRIGGER IF NOT EXISTS update_cert_info2 " \
53         "AFTER UPDATE ON package_cert_info " \
54         "WHEN (NEW.package_count = OLD.package_count + 1) " \
55         "BEGIN" \
56         " UPDATE package_cert_index_info SET" \
57         "  cert_ref_count = cert_ref_count - 1" \
58         " WHERE cert_id = OLD.author_root_cert" \
59         "  OR cert_id = OLD.author_im_cert" \
60         "  OR cert_id = OLD.author_signer_cert" \
61         "  OR cert_id = OLD.dist_root_cert" \
62         "  OR cert_id = OLD.dist_im_cert" \
63         "  OR cert_id = OLD.dist_signer_cert" \
64         "  OR cert_id = OLD.dist2_root_cert" \
65         "  OR cert_id = OLD.dist2_im_cert" \
66         "  OR cert_id = OLD.dist2_signer_cert;" \
67         "END;"
68
69 #define QUERY_CREATE_TRIGGER_DELETE_CERT_INFO \
70         "CREATE TRIGGER IF NOT EXISTS delete_cert_info " \
71         "AFTER DELETE ON package_cert_info " \
72         "BEGIN" \
73         " UPDATE package_cert_index_info SET" \
74         "  cert_ref_count = cert_ref_count - 1" \
75         " WHERE cert_id = OLD.author_root_cert" \
76         "  OR cert_id = OLD.author_im_cert" \
77         "  OR cert_id = OLD.author_signer_cert" \
78         "  OR cert_id = OLD.dist_root_cert" \
79         "  OR cert_id = OLD.dist_im_cert" \
80         "  OR cert_id = OLD.dist_signer_cert" \
81         "  OR cert_id = OLD.dist2_root_cert" \
82         "  OR cert_id = OLD.dist2_im_cert" \
83         "  OR cert_id = OLD.dist2_signer_cert;" \
84         "END;"
85
86 #define QUERY_CREATE_TRIGGER_UPDATE_CERT_INDEX_INFO \
87         "CREATE TRIGGER IF NOT EXISTS update_cert_index_info " \
88         "AFTER UPDATE ON package_cert_index_info " \
89         "WHEN ((SELECT cert_ref_count FROM package_cert_index_info " \
90         "       WHERE cert_id = OLD.cert_id) = 0) "\
91         "BEGIN" \
92         " DELETE FROM package_cert_index_info WHERE cert_id = OLD.cert_id;" \
93         "END;"
94
95 __thread db_handle manifest_db;
96 __thread db_handle cert_db;
97
98 typedef int (*sqlite_query_callback)(void *data, int ncols, char **coltxt, char **colname);
99
100 static int _mkdir_for_user(const char* dir, uid_t uid, gid_t gid)
101 {
102         int ret;
103         char *fullpath;
104         char *subpath;
105         char buf[1024];
106         int fd;
107         struct stat sb;
108
109         fullpath = strdup(dir);
110         if (fullpath == NULL)
111                 return -1;
112         subpath = dirname(fullpath);
113         if (strlen(subpath) > 1 && strcmp(subpath, fullpath) != 0) {
114                 ret = _mkdir_for_user(fullpath, uid, gid);
115                 if (ret == -1) {
116                         free(fullpath);
117                         return ret;
118                 }
119         }
120
121         ret = mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
122         if (ret && errno != EEXIST) {
123                 free(fullpath);
124                 return ret;
125         } else if (ret && errno == EEXIST) {
126                 free(fullpath);
127                 return 0;
128         }
129
130         if (getuid() == ROOT_UID) {
131                 fd = open(dir, O_RDONLY);
132                 if (fd == -1) {
133                         _LOGE("FAIL : open %s : %s", dir,
134                                         strerror_r(errno, buf, sizeof(buf)));
135                         return -1;
136                 }
137                 ret = fstat(fd, &sb);
138                 if (ret == -1) {
139                         _LOGE("FAIL : fstat %s : %s", dir,
140                                         strerror_r(errno, buf, sizeof(buf)));
141                         close(fd);
142                         return -1;
143                 }
144                 if (S_ISLNK(sb.st_mode)) {
145                         _LOGE("FAIL : %s is symlink!", dir);
146                         close(fd);
147                         return -1;
148                 }
149                 ret = fchown(fd, uid, gid);
150                 if (ret == -1) {
151                         _LOGE("FAIL : fchown %s %d.%d, because %s", dir, uid,
152                                         gid, strerror_r(errno, buf, sizeof(buf)));
153                         close(fd);
154                         return -1;
155                 }
156                 close(fd);
157         }
158
159         free(fullpath);
160
161         return 0;
162 }
163
164 static char *_get_db_path(uid_t uid)
165 {
166         const char *db_path;
167         char path[PATH_MAX];
168
169         db_path = tzplatform_getenv(TZ_SYS_DB);
170         if (db_path == NULL) {
171                 _LOGE("Failed to get TZ_SYS_DB path");
172                 return NULL;
173         }
174
175         if (uid == GLOBAL_USER || uid == ROOT_UID)
176                 return strdup(db_path);
177
178         snprintf(path, sizeof(path), "%s/user/%d", db_path, uid);
179
180         return strdup(path);
181 }
182
183 static int __attach_and_create_view(sqlite3 *handle, const char *db, const char *tables[], uid_t uid)
184 {
185         int i;
186         char *err = NULL;
187         char query[MAX_QUERY_LEN];
188
189         if (uid != GLOBAL_USER && uid != ROOT_UID) {
190                 snprintf(query, sizeof(query), "ATTACH DATABASE '%s' AS Global", db);
191                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
192                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
193                         sqlite3_free(err);
194                         return SQLITE_ERROR;
195                 }
196         }
197
198         for (i = 0; tables[i]; i++) {
199                 if (uid != GLOBAL_USER && uid != ROOT_UID)
200                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
201                                         FROM (SELECT *,0 AS for_all_users FROM main.'%s' UNION \
202                                         SELECT *,1 AS for_all_users FROM Global.'%s')",
203                                         tables[i], tables[i], tables[i]);
204                 else
205                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
206                                         FROM (SELECT *,1 AS for_all_users FROM main.'%s')",
207                                         tables[i], tables[i]);
208                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
209                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
210                         sqlite3_free(err);
211                 }
212         }
213
214         return SQLITE_OK;
215 }
216
217 static int __exec_db_query(sqlite3 *db, char *query, sqlite_query_callback callback, void *data)
218 {
219         char *error_message = NULL;
220         int ret = sqlite3_exec(db, query, callback, data, &error_message);
221         if (SQLITE_OK != ret) {
222                 _LOGE("Don't execute query = %s error message = %s   ret = %d\n", query,
223                        error_message, ret);
224                 sqlite3_free(error_message);
225                 return -1;
226         }
227         sqlite3_free(error_message);
228         return 0;
229 }
230
231 int _check_create_cert_db(sqlite3 *certdb)
232 {
233         int ret = 0;
234         ret = __exec_db_query(certdb, QUERY_CREATE_TABLE_PACKAGE_CERT_INDEX_INFO, NULL, NULL);
235         if (ret < 0)
236                 return ret;
237         ret = __exec_db_query(certdb, QUERY_CREATE_TABLE_PACKAGE_CERT_INFO, NULL, NULL);
238         if (ret < 0)
239                 return ret;
240         ret = __exec_db_query(certdb, QUERY_CREATE_TRIGGER_UPDATE_CERT_INFO, NULL, NULL);
241         if (ret < 0)
242                 return ret;
243         ret = __exec_db_query(certdb, QUERY_CREATE_TRIGGER_UPDATE_CERT_INFO2, NULL, NULL);
244         if (ret < 0)
245                 return ret;
246         ret = __exec_db_query(certdb, QUERY_CREATE_TRIGGER_DELETE_CERT_INFO, NULL, NULL);
247         if (ret < 0)
248                 return ret;
249         ret = __exec_db_query(certdb, QUERY_CREATE_TRIGGER_UPDATE_CERT_INDEX_INFO, NULL, NULL);
250         return ret;
251 }
252 static gid_t _get_gid(const char *name)
253 {
254         char buf[BUFSIZE];
255         struct group entry;
256         struct group *ge;
257         int ret;
258
259         ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge);
260         if (ret || ge == NULL) {
261                 _LOGE("fail to get gid of %s", name);
262                 return -1;
263         }
264
265         return entry.gr_gid;
266 }
267
268 API const char *getIconPath(uid_t uid, bool readonly)
269 {
270         const char *path = NULL;
271         uid_t uid_caller = getuid();
272         gid_t gid = ROOT_UID;
273
274         if (uid != GLOBAL_USER && uid != ROOT_UID) {
275                 _LOGD("not supported target user");
276                 return NULL;
277         }
278
279         if (readonly)
280                 path = tzplatform_mkpath(TZ_SYS_RO_ICONS, "/");
281
282         /* just allow certain users to create the icon directory if needed. */
283         if (path && (uid_caller == ROOT_UID  ||
284                 uid_caller == APPFW_UID || uid_caller == uid))
285                 _mkdir_for_user(path, uid, gid);
286
287         return path;
288 }
289
290 API char *getUserPkgParserDBPath(void)
291 {
292         return getUserPkgParserDBPathUID(_getuid());
293 }
294
295 API char *getUserPkgParserDBPathUID(uid_t uid)
296 {
297         char pkgmgr_parser_db[PATH_MAX];
298         uid_t uid_caller = getuid();
299         gid_t gid = ROOT_UID;
300         char *db_path;
301
302         db_path = _get_db_path(uid);
303         if (db_path == NULL) {
304                 _LOGE("Failed to get db path %d", uid);
305                 return NULL;
306         }
307         snprintf(pkgmgr_parser_db, sizeof(pkgmgr_parser_db),
308                         "%s/.pkgmgr_parser.db", db_path);
309
310         if (uid != GLOBAL_USER && uid != ROOT_UID) {
311                 tzplatform_set_user(uid);
312                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
313                 tzplatform_reset_user();
314         }
315
316         /* just allow certain users to create the dbspace directory if needed. */
317         if (uid_caller == ROOT_UID  || uid_caller == APPFW_UID || uid_caller == uid)
318                 _mkdir_for_user(db_path, uid, gid);
319
320         free(db_path);
321
322         return strdup(pkgmgr_parser_db);
323 }
324
325 API char *getUserPkgCertDBPath(void)
326 {
327          return getUserPkgCertDBPathUID(_getuid());
328 }
329
330 API char *getUserPkgCertDBPathUID(uid_t uid)
331 {
332         char pkgmgr_cert_db[PATH_MAX];
333         uid_t uid_caller = getuid();
334         gid_t gid = ROOT_UID;
335         char *db_path;
336
337         db_path = _get_db_path(uid);
338         if (db_path == NULL) {
339                 _LOGE("Failed to get db path %d", uid);
340                 return NULL;
341         }
342         snprintf(pkgmgr_cert_db, sizeof(pkgmgr_cert_db),
343                         "%s/.pkgmgr_cert.db", db_path);
344
345         if (uid != GLOBAL_USER && uid != ROOT_UID) {
346                 tzplatform_set_user(uid);
347                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
348                 tzplatform_reset_user();
349         }
350
351         /* just allow certain users to create the dbspace directory if needed. */
352         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
353                 _mkdir_for_user(db_path, uid, gid);
354
355         free(db_path);
356
357         return strdup(pkgmgr_cert_db);
358 }
359
360 API const char *getUserManifestPath(uid_t uid, bool readonly)
361 {
362         const char *path = NULL;
363         uid_t uid_caller = getuid();
364         gid_t gid = ROOT_UID;
365
366         if (uid != GLOBAL_USER && uid != ROOT_UID) {
367                 tzplatform_set_user(uid);
368                 path = tzplatform_mkpath(TZ_USER_PACKAGES, "/");
369                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
370                 tzplatform_reset_user();
371         } else {
372                 if (readonly)
373                         path = tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/");
374                 else
375                         path = tzplatform_mkpath(TZ_SYS_RW_PACKAGES, "/");
376         }
377
378         /* just allow certain users to create the icon directory if needed. */
379         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
380                 _mkdir_for_user(path, uid, gid);
381
382         return path;
383 }
384
385 int __close_manifest_db(void)
386 {
387         if (manifest_db.ref) {
388                 if (--manifest_db.ref == 0)
389                         sqlite3_close(GET_DB(manifest_db));
390                 return 0;
391         }
392         return -1;
393 }
394
395 static const char *parserdb_tables[] = {
396         "package_app_app_category",
397         "package_app_info",
398         "package_app_app_control",
399         "package_app_localized_info",
400         "package_app_app_metadata",
401         "package_app_share_allowed",
402         "package_app_app_permission",
403         "package_app_share_request",
404         "package_info",
405         "package_app_data_control",
406         "package_localized_info",
407         "package_app_icon_section_info",
408         "package_privilege_info",
409         "package_app_image_info",
410         NULL
411 };
412
413 int __open_manifest_db(uid_t uid, bool readonly)
414 {
415         int ret;
416         char *user_pkg_parser;
417         int flags;
418
419         if (manifest_db.ref) {
420                 manifest_db.ref++;
421                 return 0;
422         }
423
424         user_pkg_parser = getUserPkgParserDBPathUID(uid);
425         if (user_pkg_parser == NULL) {
426                 _LOGE("Failed to get pkg parser db path - %d", uid);
427                 return -1;
428         }
429
430         if (access(user_pkg_parser, F_OK) != 0) {
431                 _LOGE("Manifest DB does not exists !!");
432                 free(user_pkg_parser);
433                 return -1;
434         }
435
436         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
437         ret = db_util_open_with_options(user_pkg_parser, &GET_DB(manifest_db),
438                         flags, NULL);
439         if (ret != SQLITE_OK) {
440                 _LOGE("connect db [%s] failed!\n", user_pkg_parser);
441                 free(user_pkg_parser);
442                 return -1;
443         }
444
445         manifest_db.ref++;
446         if (readonly) {
447                 ret = __attach_and_create_view(GET_DB(manifest_db), MANIFEST_DB,
448                                 parserdb_tables, uid);
449                 if (ret != SQLITE_OK) {
450                         _LOGE("attach db [%s] failed!\n", user_pkg_parser);
451                         free(user_pkg_parser);
452                         return -1;
453                 }
454         }
455
456         free(user_pkg_parser);
457
458         return 0;
459 }
460
461 int __close_cert_db(void)
462 {
463         if (cert_db.ref) {
464                 if (--cert_db.ref == 0)
465                         sqlite3_close_v2(GET_DB(cert_db));
466                 return 0;
467         }
468         _LOGE("Certificate DB is already closed !!\n");
469         return -1;
470 }
471
472 static const char *certdb_tables[] = {
473         "package_cert_index_info",
474         "package_cert_info",
475         NULL
476 };
477
478 int __open_cert_db(uid_t uid, bool readonly)
479 {
480         int ret;
481         char *user_cert_parser;
482         int flags;
483
484         if (cert_db.ref) {
485                 cert_db.ref++;
486                 return 0;
487         }
488
489         user_cert_parser = getUserPkgCertDBPathUID(uid);
490         if (user_cert_parser == NULL) {
491                 _LOGE("Failed to get pkg cert db path - %d", uid);
492                 return -1;
493         }
494
495         if (access(user_cert_parser, F_OK) != 0) {
496                 _LOGE("Cert DB does not exists !!");
497                 free(user_cert_parser);
498                 return -1;
499         }
500
501         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
502         ret = db_util_open_with_options(user_cert_parser, &GET_DB(cert_db),
503                         flags, NULL);
504         if (ret != SQLITE_OK) {
505                 _LOGE("connect db [%s] failed!", user_cert_parser);
506                 free(user_cert_parser);
507                 return -1;
508         }
509         cert_db.ref++;
510         if (readonly) {
511                 ret = __attach_and_create_view(GET_DB(cert_db), CERT_DB,
512                                 certdb_tables, uid);
513                 if (ret != SQLITE_OK) {
514                         _LOGE("attach db [%s] failed!", user_cert_parser);
515                         free(user_cert_parser);
516                         return -1;
517                 }
518         }
519
520         free(user_cert_parser);
521
522         return 0;
523 }
524
525 void _save_column_int(sqlite3_stmt *stmt, int idx, int *i)
526 {
527         *i = sqlite3_column_int(stmt, idx);
528 }
529
530 void _save_column_str(sqlite3_stmt *stmt, int idx, char **str)
531 {
532         const char *val;
533
534         val = (const char *)sqlite3_column_text(stmt, idx);
535         if (val)
536                 *str = strdup(val);
537 }
538
539 API int pkgmgrinfo_pkginfo_set_usr_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path, uid_t uid)
540 {
541         retvm_if(pkgid == NULL, PMINFO_R_EINVAL, "pkgid is NULL\n");
542         int ret = -1;
543         sqlite3 *pkgmgr_parser_db = NULL;
544         char *query = NULL;
545         char *db_path;
546
547         db_path = getUserPkgParserDBPathUID(uid);
548         if (db_path == NULL) {
549                 _LOGE("Failed to get pkg parser db path - %d", uid);
550                 return PMINFO_R_ERROR;
551         }
552
553         ret = db_util_open_with_options(db_path, &pkgmgr_parser_db,
554                         SQLITE_OPEN_READWRITE, NULL);
555         if (ret != SQLITE_OK) {
556                 _LOGE("connect db failed!");
557                 free(db_path);
558                 return PMINFO_R_ERROR;
559         }
560         free(db_path);
561
562         /*Begin transaction*/
563         /* Setting Manifest DB */
564         ret = sqlite3_exec(pkgmgr_parser_db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
565         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Failed to begin transaction\n");
566         _LOGD("Transaction Begin\n");
567
568         /* pkgcakge_info table */
569         query = sqlite3_mprintf(
570                         "update package_info set installed_storage=%Q, external_path=%Q where package=%Q",
571                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
572
573         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
574         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
575         sqlite3_free(query);
576
577         /* package_app_info table */
578         query = sqlite3_mprintf(
579                         "update package_app_info set app_installed_storage=%Q, app_external_path=%Q where package=%Q",
580                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
581
582         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
583         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
584
585         /*Commit transaction*/
586         ret = sqlite3_exec(pkgmgr_parser_db, "COMMIT", NULL, NULL, NULL);
587         if (ret != SQLITE_OK) {
588                 _LOGE("Failed to commit transaction. Rollback now\n");
589                 ret = sqlite3_exec(pkgmgr_parser_db, "ROLLBACK", NULL, NULL, NULL);
590                 tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
591         }
592         _LOGD("Transaction Commit and End\n");
593
594         ret = PMINFO_R_OK;
595 catch:
596         sqlite3_close(pkgmgr_parser_db);
597         sqlite3_free(query);
598         return ret;
599 }
600
601 API int pkgmgrinfo_pkginfo_set_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path)
602 {
603         return pkgmgrinfo_pkginfo_set_usr_installed_storage(pkgid, location, external_pkg_path, _getuid());
604 }