Fix build warning based on GCC-9
[platform/core/appfw/alarm-manager.git] / server / alarm-manager-util.c
1 /*
2  * Copyright (c) 2019 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 #include <fcntl.h>
19 #include <system_info.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24
25 #include <aul.h>
26 #include <cert-svc/ccert.h>
27 #include <cert-svc/cinstance.h>
28 #include <cynara-session.h>
29 #include <cynara-client.h>
30 #include <cynara-creds-gdbus.h>
31 #include <tzplatform_config.h>
32
33 #include "alarm-manager-util.h"
34
35 #define ALARMMGR_LOG_BUFFER_SIZE        10000
36 #define ALARMMGR_LOG_BUFFER_STRING_SIZE 400
37 #define ALARMMGR_LOG_DIR_PATH   "/var/log/appfw/alarmmgr_log/"
38 #define ALARMMGR_LOG_FILE_PATH  "/var/log/appfw/alarmmgr_log/alarmmgr.log"
39 static int log_index = 0;
40 static int log_fd = 0;
41
42 static int __bg_category_func(const char *name, void *user_data)
43 {
44         bg_category_cb_info_t *info = (bg_category_cb_info_t *)user_data;
45         LOGD("appid[%s], bg name = %s", info->appid, name);
46         if (name && strncmp("enable", name, strlen(name)) &&
47                         strncmp("disable", name, strlen(name))) {
48                 info->has_bg = true;
49                 return -1;
50         }
51
52         return 0;
53 }
54
55 profile_t _get_profile()
56 {
57         static profile_t saved = PROFILE_UNKNOWN;
58         char *profileName;
59         int r;
60
61         if (__builtin_expect(saved != PROFILE_UNKNOWN, 1))
62                 return saved;
63
64         r = system_info_get_platform_string("http://tizen.org/feature/profile",
65                         &profileName);
66         if (r != SYSTEM_INFO_ERROR_NONE) {
67                 LOGD("Failed to get profile info. error(%d)", r);
68                 return saved;
69         }
70
71         switch (*profileName) {
72         case 'm':
73         case 'M':
74                 saved = PROFILE_MOBILE;
75                 break;
76         case 'w':
77         case 'W':
78                 saved = PROFILE_WEARABLE;
79                 break;
80         case 't':
81         case 'T':
82                 saved = PROFILE_TV;
83                 break;
84         case 'i':
85         case 'I':
86                 saved = PROFILE_IVI;
87                 break;
88         default: // common or unknown ==> ALL ARE COMMON.
89                 saved = PROFILE_COMMON;
90         }
91         free(profileName);
92
93         return saved;
94 }
95
96 int _pkg_is_global(const char *callee_pkgid, uid_t uid)
97 {
98         int retval;
99         int return_code = ERR_ALARM_SYSTEM_FAIL;
100         pkgmgrinfo_pkginfo_h handle;
101
102         retval = pkgmgrinfo_pkginfo_get_usr_pkginfo(callee_pkgid, uid, &handle);
103         if (retval != PMINFO_R_OK) {
104                 LOGE("Failed to get pkginfo\n");
105                 return_code = ERR_ALARM_INVALID_ID;
106         } else {
107                 bool is_global = 0;
108                 retval = pkgmgrinfo_pkginfo_is_global(handle, &is_global);
109                 if (retval == PMINFO_R_OK && is_global)
110                         return_code = ALARMMGR_RESULT_SUCCESS;
111                 else if (retval == PMINFO_R_OK && !is_global)
112                         return_code = ERR_ALARM_NOT_PERMITTED_APP;
113
114                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
115         }
116
117         return return_code;
118 }
119
120 int _cynara_check(GDBusMethodInvocation *invocation, const char *privilege,
121                 pid_t pid)
122 {
123         int ret = 0;
124         char *user = NULL;
125         char *client = NULL;
126         char *client_session = NULL;
127         cynara *p_cynara = NULL;
128         const char *sender_unique_name;
129         GDBusConnection *connection;
130
131         connection = g_dbus_method_invocation_get_connection(invocation);
132         sender_unique_name = g_dbus_method_invocation_get_sender(invocation);
133
134         ret = cynara_initialize(&p_cynara, NULL);
135         if (ret != CYNARA_API_SUCCESS) {
136                 LOGE("cynara_initialize() failed : %d", ret);
137                 ret = ERR_ALARM_SYSTEM_FAIL;
138                 goto cynara_out;
139         }
140
141         ret = cynara_creds_gdbus_get_user(connection, sender_unique_name,
142                         USER_METHOD_DEFAULT, &user);
143         if (ret != CYNARA_API_SUCCESS) {
144                 LOGE("cynara_creds_gdbus_get_user() failed : %d", ret);
145                 ret = ERR_ALARM_SYSTEM_FAIL;
146                 goto cynara_out;
147         }
148
149         ret = cynara_creds_gdbus_get_client(connection, sender_unique_name,
150                         CLIENT_METHOD_DEFAULT, &client);
151         if (ret != CYNARA_API_SUCCESS) {
152                 LOGE("cynara_creds_gdbus_get_client() failed : %d", ret);
153                 ret = ERR_ALARM_SYSTEM_FAIL;
154                 goto cynara_out;
155         }
156
157         LOGD("user :%s , client :%s ,unique_name : %s, pid() : %d",
158                         user, client, sender_unique_name, pid);
159
160         client_session = cynara_session_from_pid(pid);
161         if (!client_session) {
162                 LOGE("cynara_session_from_pid() failed : %d", ret);
163                 ret = ERR_ALARM_SYSTEM_FAIL;
164                 goto cynara_out;
165         }
166
167         ret = cynara_check(p_cynara, client, client_session, user,
168                         privilege);
169         if (ret == CYNARA_API_ACCESS_ALLOWED) {
170                 LOGD("CYNARA_ACCESS_ALLOWED");
171                 ret = ALARMMGR_RESULT_SUCCESS;
172         }
173         else {
174                 LOGD("CYNARA_NOT_ALLOWED [%d]", ret);
175                 ret = ERR_ALARM_NOT_PERMITTED_APP;
176         }
177
178 cynara_out:
179         if (client_session)
180                 g_free(client_session);
181         if (client)
182                 g_free(client);
183         if (user)
184                 g_free(user);
185         if (p_cynara)
186                 cynara_finish(p_cynara);
187
188         return ret;
189 }
190
191 int _get_pid_from_appid(const char *app_id, uid_t uid)
192 {
193         int pid;
194         pid = aul_app_get_pid_for_uid(app_id, uid);
195         if (pid < 0) {
196                 LOGE("aul_app_get_pid_for_uid() is failed. appid %s may not be app. uid : [%d]", app_id, uid);
197                 return 0;
198         }
199
200         LOGD("app_id:%s [pid:%d]", app_id, pid);
201         return pid;
202 }
203
204 char *_get_pkgid_by_appid(const char *app_id, uid_t uid)
205 {
206         pkgmgrinfo_pkginfo_h handle;
207         char *pkgid = NULL;
208         char *temp;
209
210         if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id, uid, &handle) == PMINFO_R_OK) {
211                 if (pkgmgrinfo_appinfo_get_pkgid(handle, &temp) == PMINFO_R_OK) {
212                         if (temp)
213                                 pkgid = strdup(temp);
214                 }
215                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
216         }
217
218         return pkgid;
219 }
220
221 int _is_ui_app(const char *appid, uid_t uid)
222 {
223         int ret = 0;
224         int found = 0;
225         char *component = NULL;
226         pkgmgrinfo_appinfo_h appinfo_h = NULL;
227
228         if (appid == NULL)
229                 return 0;
230
231         ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &appinfo_h);
232         if (ret < 0)
233                 return 0;
234
235         ret = pkgmgrinfo_appinfo_get_component_type(appinfo_h, &component);
236         if (ret == 0 && component != NULL && strncmp(component, "uiapp", 5) == 0)
237                 found = 1;
238
239         if (appinfo_h)
240                 pkgmgrinfo_appinfo_destroy_appinfo(appinfo_h);
241
242         return found;
243 }
244
245 bool _is_app(const char *appid, uid_t uid)
246 {
247         pkgmgrinfo_appinfo_h appinfo_h = NULL;
248         int ret;
249
250         ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &appinfo_h);
251         if (ret != PMINFO_R_OK)
252                 return false;
253
254         if (appinfo_h)
255                 pkgmgrinfo_appinfo_destroy_appinfo(appinfo_h);
256
257         return true;
258 }
259
260 int _compare_api_version(int *result, int pid, uid_t uid)
261 {
262         int ret = 0;
263         pkgmgrinfo_pkginfo_h pkginfo = NULL;
264         char pkgid[MAX_PKG_ID_LEN] = {0, };
265         char *pkg_version;
266
267         if (aul_app_get_pkgid_bypid_for_uid(pid, pkgid, sizeof(pkgid), uid) != AUL_R_OK) {
268                 LOGE("aul_app_get_pkgid_bypid() is failed. PID %d may not be app.", getpid());
269         } else {
270                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &pkginfo);
271                 if (ret != PMINFO_R_OK) {
272                         LOGE("Failed to get pkginfo\n");
273                 } else {
274                         ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo, &pkg_version);
275                         if (ret != PMINFO_R_OK)
276                                 LOGE("Failed to check api version [%d]\n", ret);
277                         *result = strverscmp(pkg_version, "2.4");
278                         pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
279                 }
280         }
281         return ret;
282 }
283
284 bool _permit_by_config(pkgmgrinfo_appinfo_h handle, uid_t uid)
285 {
286         if (access(tzplatform_mkpath(TZ_SYS_RO_SHARE,
287                                         "alarm-manager/alarm-config-service-restricted"), F_OK) == 0) {
288                 LOGD("This profile restrict alarms for service applications\n");
289                 return false;
290         }
291
292         if (access(tzplatform_mkpath(TZ_SYS_RO_SHARE,
293                                         "alarm-manager/alarm-config-platform-service-permitted"), F_OK) == 0) {
294                 LOGD("This profile permit alarm for service applications which has platform cert\n");
295                 char *pkgid;
296                 int r;
297                 const char *cert_value;
298                 pkgmgrinfo_certinfo_h certinfo;
299                 CertSvcInstance instance;
300                 CertSvcCertificate certificate;
301                 CertSvcVisibility visibility = CERTSVC_VISIBILITY_PUBLIC;
302
303                 r = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
304                 if (r != PMINFO_R_OK) {
305                         LOGE("Failed to get certinfo pkgid");
306                         return false;
307                 }
308
309                 r = pkgmgrinfo_pkginfo_create_certinfo(&certinfo);
310                 if (r != PMINFO_R_OK) {
311                         LOGE("Failed to create certinfo");
312                         return false;
313                 }
314
315                 r = pkgmgrinfo_pkginfo_load_certinfo(pkgid, certinfo, uid);
316                 if (r != PMINFO_R_OK) {
317                         LOGE("Failed to load certinfo");
318                         pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
319                         return false;
320                 }
321
322                 r = pkgmgrinfo_pkginfo_get_cert_value(certinfo,
323                                 PMINFO_DISTRIBUTOR_ROOT_CERT, &cert_value);
324                 if (r != PMINFO_R_OK || cert_value == NULL) {
325                         LOGE("Failed to get cert value");
326                         pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
327                         return false;
328                 }
329
330                 r = certsvc_instance_new(&instance);
331                 if (r != CERTSVC_SUCCESS) {
332                         LOGE("certsvc_instance_new() is failed.");
333                         pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
334                         return false;
335                 }
336
337                 r = certsvc_certificate_new_from_memory(instance,
338                                 (const unsigned char *)cert_value,
339                                 strlen(cert_value),
340                                 CERTSVC_FORM_DER_BASE64,
341                                 &certificate);
342                 if (r != CERTSVC_SUCCESS) {
343                         LOGE("certsvc_certificate_new_from_memory() is failed.");
344                         pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
345                         certsvc_instance_free(instance);
346                         return false;
347                 }
348
349                 r = certsvc_certificate_get_visibility(certificate, &visibility);
350                 if (r != CERTSVC_SUCCESS)
351                         LOGE("certsvc_certificate_get_visibility() is failed.");
352
353                 pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
354                 certsvc_instance_free(instance);
355                 certsvc_certificate_free(certificate);
356
357                 LOGW("visibility is %d", visibility);
358                 if (visibility & CERTSVC_VISIBILITY_PLATFORM) {
359                         return true;
360                 }
361         }
362
363         if (access(tzplatform_mkpath(TZ_SYS_RO_SHARE,
364                                         "alarm-manager/alarm-config-all-service-permitted"), F_OK) == 0) {
365                 LOGD("This profile permit alarms for all service applications\n");
366                 return true;
367         }
368
369         return false;
370 }
371
372 bool _is_permitted(const char *app_id, int alarm_type, uid_t uid)
373 {
374         pkgmgrinfo_appinfo_h handle = NULL;
375         int ret;
376         bool _return = false;
377
378         if (app_id == NULL) {
379                 LOGE("app_id is NULL. Only expicit launch is permitted\n");
380                 return false;
381         }
382
383         ret = pkgmgrinfo_appinfo_get_usr_appinfo(app_id, uid, &handle);
384         if (ret != PMINFO_R_OK) {
385                 LOGE("Failed to get appinfo [%s]\n", app_id);
386         } else {
387                 char *app_type = NULL;
388                 ret = pkgmgrinfo_appinfo_get_component_type(handle, &app_type);
389                 if (app_type && strcmp("uiapp", app_type) == 0) {
390                         if (alarm_type & ALARM_TYPE_EXACT_SERVICE_APP) {
391                                 LOGE("[%s] is ui application.\
392                                                 But alarm_type is ALARM_TYPE_EXACT_SERVICE_APP.\
393                                                 soit is not allowed", app_id);
394                                 _return = false;
395                                 goto out;
396                         }
397                         LOGD("[%s] is ui application. It is allowed", app_id);
398                         _return = true;
399                         goto out;
400                 } else if (app_type && strcmp("svcapp", app_type) == 0) {
401                         LOGD("[%s] is service application.", app_id);
402
403                         if (_permit_by_config(handle, uid)) {
404                                 LOGD("service applications are allowed");
405                                 _return = true;
406                                 goto out;
407                         }
408
409                         bg_category_cb_info_t info = {
410                                 .appid = app_id,
411                                 .has_bg = false
412                         };
413
414                         if (alarm_type & ALARM_TYPE_INEXACT || alarm_type & ALARM_TYPE_EXACT_SERVICE_APP) {
415                                 ret = pkgmgrinfo_appinfo_foreach_background_category(handle, __bg_category_func, &info);
416                                 if (ret == PMINFO_R_OK && info.has_bg) {
417                                         LOGD("[%s] has background categories. It is allowed", app_id);
418                                         _return = true;
419                                         goto out;
420                                 } else {
421                                         LOGE("Failed to foreach background category. [%s] is not allowed", app_id);
422                                 }
423                         }
424                 }
425         }
426
427 out:
428         if (handle)
429                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
430
431         return _return;
432 }
433
434 void _initialize_module_log(void)
435 {
436 #ifdef _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG
437         char buf[1024];
438
439         if (access(ALARMMGR_LOG_DIR_PATH, F_OK)) {
440                 LOGE("Not exist(%s)", ALARMMGR_LOG_DIR_PATH);
441
442                 if (mkdir(ALARMMGR_LOG_DIR_PATH, (S_IRUSR | S_IWUSR | S_IXUSR |
443                                         S_IRGRP | S_IWGRP | S_IXGRP))) {
444                         LOGE("Failed to create directory(%s). errno(%d)",
445                                         ALARMMGR_LOG_DIR_PATH, errno);
446                         return;
447                 }
448         }
449
450         log_fd = open(ALARMMGR_LOG_FILE_PATH, O_CREAT | O_WRONLY, 0644);
451         if (log_fd == -1) {
452                 LOGE("Opening the file for alarmmgr log is failed. err: %s", strerror_r(errno, buf, sizeof(buf)));
453                 return;
454         }
455
456         int offset = lseek(log_fd, 0, SEEK_END);
457         if (offset != 0) {
458                 log_index = (int)(offset / ALARMMGR_LOG_BUFFER_STRING_SIZE);
459                 if (log_index >= ALARMMGR_LOG_BUFFER_SIZE) {
460                         log_index = 0;
461                         lseek(log_fd, 0, SEEK_SET);
462                 }
463         }
464 #endif /* _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG */
465         return;
466 }
467
468 void _save_module_log(const char *tag, const char *message)
469 {
470 #ifdef _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG
471         char buffer[ALARMMGR_LOG_BUFFER_STRING_SIZE] = {0,};
472         time_t now;
473         char buf[1024];
474         char *time_str;
475
476         if (log_fd == -1) {
477                 LOGE("The file is not ready.");
478                 return;
479         }
480
481         if (log_index != 0)
482                 lseek(log_fd, 0, SEEK_CUR);
483         else
484                 lseek(log_fd, 0, SEEK_SET);
485
486         time(&now);
487         time_str = ctime(&now);
488         if (time_str)
489                 time_str[strlen(time_str) - 1] = '\0'; /* to avoid new line */
490
491         snprintf(buffer, ALARMMGR_LOG_BUFFER_STRING_SIZE, "[%-6d]%s\t%s\t : %ld %s\n", log_index, tag, message, now, time_str);
492
493         SECURE_LOGW("%s", buffer);
494         int ret = write(log_fd, buffer, strlen(buffer));
495         if (ret < 0) {
496                 LOGE("Writing the alarmmgr log is failed. err: %s", strerror_r(errno, buf, sizeof(buf)));
497                 return;
498         }
499
500         if (++log_index >= ALARMMGR_LOG_BUFFER_SIZE)
501                 log_index = 0;
502 #endif /* _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG */
503         return;
504 }
505
506 void _save_alarm_info_log(const char *tag, __alarm_info_t *info)
507 {
508 #ifdef _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG
509         char log_message[ALARMMGR_LOG_MESSAGE_SIZE] = {0,};
510         char *due_time_str = ctime(&(info->due_time));
511         if (due_time_str)
512                 due_time_str[strlen(due_time_str) - 1] = '\0'; /* to avoid new line */
513         else
514                 due_time_str = "NULL";
515
516         snprintf(log_message, sizeof(log_message),
517                 "alarmID: %d, uid: %d, caller : %s -> callee : %s, "
518                 "dst_name %s, dst_mod %s, "
519                 "type 0x%x, mode %d, "
520                 "interval:%ld, duetime: %ld %s",
521                 info->alarm_id, info->uid, info->app_unique_name, info->callee_pkgid,
522                 info->dst_service_name, info->dst_service_name_mod,
523                 info->alarm_info.alarm_type, info->alarm_info.mode.repeat,
524                 info->alarm_info.mode.u_interval.interval, info->due_time, due_time_str);
525
526         _save_module_log(tag, log_message);
527 #endif /* _APPFW_FEATURE_ALARM_MANAGER_MODULE_LOG */
528         return;
529 }
530