Fix memory leak
[platform/core/appfw/pkgmgr-info.git] / src / pkgmgrinfo_db.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <ctype.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <grp.h>
11 #include <dirent.h>
12 #include <libgen.h>
13
14 #include <sqlite3.h>
15
16 #include <tzplatform_config.h>
17 #include <db-util.h>
18
19 #include "pkgmgr-info.h"
20 #include "pkgmgrinfo_debug.h"
21 #include "pkgmgrinfo_private.h"
22 #include "pkgmgr_parser.h"
23 #include "pkgmgr_parser_db.h"
24
25 typedef int (*sqlite_query_callback)(void *data, int ncols, char **coltxt, char **colname);
26
27 static int _mkdir_for_user(const char* dir, uid_t uid, gid_t gid)
28 {
29         int ret;
30         char *fullpath;
31         char *subpath;
32         char buf[1024];
33         int fd;
34         struct stat sb;
35
36         fullpath = strdup(dir);
37         if (fullpath == NULL)
38                 return -1;
39         subpath = dirname(fullpath);
40         if (strlen(subpath) > 1 && strcmp(subpath, fullpath) != 0) {
41                 ret = _mkdir_for_user(fullpath, uid, gid);
42                 if (ret == -1) {
43                         free(fullpath);
44                         return ret;
45                 }
46         }
47
48         ret = mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
49         if (ret && errno != EEXIST) {
50                 free(fullpath);
51                 return ret;
52         } else if (ret && errno == EEXIST) {
53                 free(fullpath);
54                 return 0;
55         }
56
57         if (getuid() == ROOT_UID) {
58                 fd = open(dir, O_RDONLY);
59                 if (fd == -1) {
60                         _LOGE("FAIL : open %s : %s", dir,
61                                         strerror_r(errno, buf, sizeof(buf)));
62                         return -1;
63                 }
64                 ret = fstat(fd, &sb);
65                 if (ret == -1) {
66                         _LOGE("FAIL : fstat %s : %s", dir,
67                                         strerror_r(errno, buf, sizeof(buf)));
68                         close(fd);
69                         return -1;
70                 }
71                 if (S_ISLNK(sb.st_mode)) {
72                         _LOGE("FAIL : %s is symlink!", dir);
73                         close(fd);
74                         return -1;
75                 }
76                 ret = fchown(fd, uid, gid);
77                 if (ret == -1) {
78                         _LOGE("FAIL : fchown %s %d.%d, because %s", dir, uid,
79                                         gid, strerror_r(errno, buf, sizeof(buf)));
80                         close(fd);
81                         return -1;
82                 }
83                 close(fd);
84         }
85
86         free(fullpath);
87
88         return 0;
89 }
90
91 static char *_get_db_path(uid_t uid)
92 {
93         const char *db_path;
94         char path[PATH_MAX];
95
96         db_path = tzplatform_getenv(TZ_SYS_DB);
97         if (db_path == NULL) {
98                 _LOGE("Failed to get TZ_SYS_DB path");
99                 return NULL;
100         }
101
102         if (uid == GLOBAL_USER || uid == ROOT_UID)
103                 return strdup(db_path);
104
105         snprintf(path, sizeof(path), "%s/user/%d", db_path, uid);
106
107         return strdup(path);
108 }
109
110 int _check_create_cert_db(void)
111 {
112         return pkgmgr_parser_initialize_cert_db();
113 }
114
115 static gid_t _get_gid(const char *name)
116 {
117         char buf[BUFSIZE];
118         struct group entry;
119         struct group *ge;
120         int ret;
121
122         ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge);
123         if (ret || ge == NULL) {
124                 _LOGE("fail to get gid of %s", name);
125                 return -1;
126         }
127
128         return entry.gr_gid;
129 }
130
131 API const char *getIconPath(uid_t uid, bool readonly)
132 {
133         const char *path = NULL;
134         uid_t uid_caller = getuid();
135         gid_t gid = ROOT_UID;
136
137         if (uid != GLOBAL_USER && uid != ROOT_UID) {
138                 _LOGD("not supported target user");
139                 return NULL;
140         }
141
142         if (readonly)
143                 path = tzplatform_mkpath(TZ_SYS_RO_ICONS, "/");
144
145         /* just allow certain users to create the icon directory if needed. */
146         if (path && (uid_caller == ROOT_UID  ||
147                 uid_caller == APPFW_UID || uid_caller == uid))
148                 _mkdir_for_user(path, uid, gid);
149
150         return path;
151 }
152
153 API char *getUserPkgParserDBPath(void)
154 {
155         return getUserPkgParserDBPathUID(_getuid());
156 }
157
158 API char *getUserPkgParserDBPathUID(uid_t uid)
159 {
160         char pkgmgr_parser_db[PATH_MAX];
161         uid_t uid_caller = getuid();
162         gid_t gid = ROOT_UID;
163         char *db_path;
164
165         db_path = _get_db_path(uid);
166         if (db_path == NULL) {
167                 _LOGE("Failed to get db path %d", uid);
168                 return NULL;
169         }
170         snprintf(pkgmgr_parser_db, sizeof(pkgmgr_parser_db),
171                         "%s/.pkgmgr_parser.db", db_path);
172         if (access(db_path, F_OK) != 0) {
173                 if (uid != GLOBAL_USER && uid != ROOT_UID) {
174                         tzplatform_set_user(uid);
175                         gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
176                         tzplatform_reset_user();
177                 }
178                 /* just allow certain users to create the dbspace directory if needed. */
179                 if (uid_caller == ROOT_UID || uid_caller == APPFW_UID ||
180                                 uid_caller == uid)
181                         _mkdir_for_user(db_path, uid, gid);
182         }
183         free(db_path);
184
185         return strdup(pkgmgr_parser_db);
186 }
187
188 API char *getUserPkgCertDBPath(void)
189 {
190          return getUserPkgCertDBPathUID(_getuid());
191 }
192
193 API char *getUserPkgCertDBPathUID(uid_t uid)
194 {
195         char pkgmgr_cert_db[PATH_MAX];
196         uid_t uid_caller = getuid();
197         gid_t gid = ROOT_UID;
198         char *db_path;
199
200         db_path = _get_db_path(uid);
201         if (db_path == NULL) {
202                 _LOGE("Failed to get db path %d", uid);
203                 return NULL;
204         }
205         snprintf(pkgmgr_cert_db, sizeof(pkgmgr_cert_db),
206                         "%s/.pkgmgr_cert.db", db_path);
207
208         if (uid != GLOBAL_USER && uid != ROOT_UID) {
209                 tzplatform_set_user(uid);
210                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
211                 tzplatform_reset_user();
212         }
213
214         /* just allow certain users to create the dbspace directory if needed. */
215         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
216                 _mkdir_for_user(db_path, uid, gid);
217
218         free(db_path);
219
220         return strdup(pkgmgr_cert_db);
221 }
222
223 API const char *getUserManifestPath(uid_t uid, bool readonly)
224 {
225         const char *path = NULL;
226         uid_t uid_caller = getuid();
227         gid_t gid = ROOT_UID;
228
229         if (uid != GLOBAL_USER && uid != ROOT_UID) {
230                 tzplatform_set_user(uid);
231                 path = tzplatform_mkpath(TZ_USER_PACKAGES, "/");
232                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
233                 tzplatform_reset_user();
234         } else {
235                 if (readonly)
236                         path = tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/");
237                 else
238                         path = tzplatform_mkpath(TZ_SYS_RW_PACKAGES, "/");
239         }
240
241         /* just allow certain users to create the icon directory if needed. */
242         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
243                 _mkdir_for_user(path, uid, gid);
244
245         return path;
246 }
247
248 void _save_column_int(sqlite3_stmt *stmt, int idx, int *i)
249 {
250         *i = sqlite3_column_int(stmt, idx);
251 }
252
253 inline void _save_column_str(sqlite3_stmt *stmt, int idx, char **str)
254 {
255         const char *val;
256
257         val = (const char *)sqlite3_column_text(stmt, idx);
258         if (val)
259                 *str = strdup(val);
260 }
261
262 API int pkgmgrinfo_pkginfo_set_usr_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path, uid_t uid)
263 {
264         retvm_if(pkgid == NULL, PMINFO_R_EINVAL, "pkgid is NULL\n");
265         int ret = -1;
266         sqlite3 *pkgmgr_parser_db = NULL;
267         char *query = NULL;
268         char *db_path;
269         const char *location_str;
270
271         db_path = getUserPkgParserDBPathUID(uid);
272         if (db_path == NULL) {
273                 _LOGE("Failed to get pkg parser db path - %d", uid);
274                 return PMINFO_R_ERROR;
275         }
276
277         ret = db_util_open_with_options(db_path, &pkgmgr_parser_db,
278                         SQLITE_OPEN_READWRITE, NULL);
279         if (ret != SQLITE_OK) {
280                 _LOGE("connect db failed!");
281                 free(db_path);
282                 return PMINFO_R_ERROR;
283         }
284         free(db_path);
285
286         /*Begin transaction*/
287         /* Setting Manifest DB */
288         ret = sqlite3_exec(pkgmgr_parser_db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
289         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Failed to begin transaction\n");
290         _LOGD("Transaction Begin\n");
291
292         if (location == INSTALL_INTERNAL)
293                 location_str = "installed_internal";
294         else if (location == INSTALL_EXTERNAL)
295                 location_str = "installed_external";
296         else
297                 location_str = "installed_extended";
298         /* pkgcakge_info table */
299         query = sqlite3_mprintf(
300                         "update package_info set installed_storage=%Q, external_path=%Q where package=%Q",
301                         location_str, external_pkg_path, pkgid);
302
303         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
304         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
305         sqlite3_free(query);
306
307         /* package_app_info table */
308         query = sqlite3_mprintf(
309                         "update package_app_info set app_installed_storage=%Q, app_external_path=%Q where package=%Q",
310                         location_str, external_pkg_path, pkgid);
311
312         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
313         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
314
315         /*Commit transaction*/
316         ret = sqlite3_exec(pkgmgr_parser_db, "COMMIT", NULL, NULL, NULL);
317         if (ret != SQLITE_OK) {
318                 _LOGE("Failed to commit transaction. Rollback now\n");
319                 ret = sqlite3_exec(pkgmgr_parser_db, "ROLLBACK", NULL, NULL, NULL);
320                 tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
321         }
322         _LOGD("Transaction Commit and End\n");
323
324         ret = PMINFO_R_OK;
325 catch:
326         sqlite3_close(pkgmgr_parser_db);
327         sqlite3_free(query);
328         return ret;
329 }
330
331 API int pkgmgrinfo_pkginfo_set_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path)
332 {
333         return pkgmgrinfo_pkginfo_set_usr_installed_storage(pkgid, location, external_pkg_path, _getuid());
334 }