strncpy() fix in wrt-launcher against buffer overflow.
[framework/web/wrt.git] / src / wrt-launcher / wrt-launcher.cpp
1 /*
2  * Copyright (c) 2011 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 #include <iostream>
17 #include <string>
18 #include <app.h>
19 #include <app_manager.h>
20 #include <string.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <pwd.h>
26 #include <sys/types.h>
27 #include <dpl/wrt-dao-ro/WrtDatabase.h>
28 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
29 #include <dpl/wrt-dao-ro/feature_dao_read_only.h>
30 #include <dpl/wrt-dao-ro/common_dao_types.h>
31 #include <dpl/wrt-dao-ro/wrt_db_types.h>
32 #include <dpl/wrt-dao-ro/config_parser_data.h>
33 #include <dpl/exception.h>
34 #include <appsvc.h>
35
36 #define TIMEOUT_DEFAULT     10
37 #define ROOT_DEFAULT_UID 0
38 #define ROOT_DEFAULT_GID 0
39 #define WEBAPP_DEFAULT_UID  5000
40 #define WEBAPP_DEFAULT_GID  5000
41 #define LOGGING_DEFAULT_GID 6509
42 #define RETURN_ERROR -1
43 #define BUF_SIZE 1024
44
45 static const char *program;
46
47 class DBConnection
48 {
49   public:
50     void AttachDatabase()
51     {
52         WrtDB::WrtDatabase::attachToThreadRW();
53     }
54
55     void DetachDatabase()
56     {
57         WrtDB::WrtDatabase::detachFromThread();
58     }
59 };
60
61 static std::unique_ptr<DBConnection> g_dbConnection;
62
63 typedef struct
64 {
65     char* guid;           /**< the widget's id
66                            * (read from its config.xml during installation)*/
67     char* name;         /**< the widget's name
68                          * (read from its config.xml during installation)*/
69     char* version;      /**< the widget's varsion
70                          * (read from its config.xml during installation)*/
71     char* pkg_id;       /**< the widget's pkg id */
72
73     char* app_id;
74 } widget_info;
75
76 static void free_widget_info(widget_info* widget_info)
77 {
78     if (widget_info) {
79         delete[] widget_info->guid;
80         delete[] widget_info->name;
81         delete[] widget_info->version;
82         delete[] widget_info->pkg_id;
83         delete[] widget_info->app_id;
84         delete widget_info;
85     }
86 }
87
88 static char* new_strdup(const char *str)
89 {
90     size_t size = strlen(str);
91     char* ret = new char[size + 1];
92     strcpy(ret, str);
93     return ret;
94 }
95
96 static bool attachDbConnection()
97 {
98     if (NULL == g_dbConnection.get()) {
99         Try {
100             g_dbConnection.reset(new DBConnection());
101             g_dbConnection->AttachDatabase();
102         }
103         Catch(DPL::DB::SqlConnection::Exception::Base) {
104             LogDebug("Fail to connect DB");
105             return FALSE;
106         }
107     }
108     return TRUE;
109 }
110
111 static bool display_widget_info()
112 {
113     if (!attachDbConnection()) {
114         return FALSE;
115     }
116
117     WidgetDAOReadOnlyList widgetList;
118
119     Try {
120         widgetList = WrtDB::WidgetDAOReadOnly::getWidgetList();
121     } Catch (WrtDB::WidgetDAOReadOnly::Exception::DatabaseError) {
122         LogError("Fail to get WidgetList");
123         return FALSE;
124     }
125
126     printf("%3s %32s %16s %64s %16s %24s\n",
127            "No", "Name", "Version", "GUID", "Package ID", "App ID");
128     printf("%3s %32s %16s %64s %16s %24s\n",
129            "--", "--", "----", "-------", "-----", "-----");
130
131     int number = 1;
132     FOREACH(dao, widgetList) {
133         widget_info *info = new widget_info;
134         memset(info, 0x00, sizeof(widget_info));
135
136         WrtDB::WidgetGUID guid = (*dao)->getGUID();
137         DPL::Optional<DPL::String> version = (*dao)->getVersion();
138         WrtDB::TizenAppId appid = (*dao)->getTzAppId();
139         WrtDB::TizenPkgId pkgid = (*dao)->getTizenPkgId();
140
141
142         /*get WidgetName*/
143         DPL::Optional<DPL::String> widget_name;
144         DPL::OptionalString dl = (*dao)->getDefaultlocale();
145         WrtDB::WidgetLocalizedInfo localizedInfo;
146         if (dl.IsNull()) {
147             DPL::String languageTag(L"");
148             localizedInfo = (*dao)->getLocalizedInfo(languageTag);
149         } else {
150             localizedInfo = (*dao)->getLocalizedInfo(*dl);
151         }
152
153         widget_name = localizedInfo.name;
154
155         /*end get WidgetName*/
156         if (!widget_name.IsNull()) {
157             info->name = new_strdup(DPL::ToUTF8String(*widget_name).c_str());
158         }
159         if (!version.IsNull()) {
160             info->version = new_strdup(DPL::ToUTF8String(*version).c_str());
161         } else {
162             std::string installedWidgetVersionString;
163             installedWidgetVersionString = "";
164             info->version = new_strdup(installedWidgetVersionString.c_str());
165         }
166         if (!guid.IsNull()) {
167             info->guid = new_strdup(DPL::ToUTF8String(*guid).c_str());
168         }
169
170         info->app_id = new_strdup(DPL::ToUTF8String(appid).c_str());
171         info->pkg_id = new_strdup(DPL::ToUTF8String(pkgid).c_str());
172
173         printf("%3i %32s %16s %64s %16s %24s\n",
174                number++,
175                !info->name ? "[NULL]" : info->name,
176                !info->version ? "[NULL]" : info->version,
177                !info->guid ? "[NULL]" : info->guid,
178                !info->pkg_id ? "[NULL]" : info->pkg_id,
179                !info->app_id ? "[NULL]" : info->app_id);
180
181         free_widget_info(info);
182     }
183
184     return 1;
185 }
186
187 static void print_help(FILE *stream, int /*exit_code*/)
188 {
189     fprintf(stream, "Usage : %s [ ... ]\n", program);
190     fprintf(
191         stream,
192         "   -h                        --help              Display this usage information.\n"
193         "   -l                        --list              Display installed widgets list\n"
194         "   -s [tizen application ID] --start             Launch widget with tizen application ID\n"
195         "   -k [tizen application ID] --kill              Kill widget with tizen application ID\n"
196         "   -r [tizen application ID] --is-running        Check whether widget is running by tizen application ID,\n"
197         "                                                 If widget is running, 0(zero) will be returned.\n"
198         "   -d                        --debug             Activate debug mode\n"
199         "   -t [second]               --timeout           Set timeout of response from widget in debug mode\n"
200         "    if you emit this option, 5 seconds is set in debug mode\n"
201         );
202 }
203
204 extern "C" int service_to_bundle(service_h service, bundle** data);
205
206 static void serviceReplyCallback(service_h /*request*/,
207                                  service_h reply,
208                                  service_result_e /*result*/,
209                                  void* data)
210 {
211     Ecore_Timer* serviceTimer = static_cast<Ecore_Timer*>(data);
212     if (serviceTimer != NULL) {
213         ecore_timer_del(serviceTimer);
214     }
215
216     bundle* b = NULL;
217     service_to_bundle(reply, &b);
218     const char* port = appsvc_get_data(b, "port");
219     if (port != NULL && strlen(port) > 0) {
220         printf("port: %s\n", port);
221         printf("result: %s\n", "launched");
222     } else {
223         printf("result: %s\n", "failed");
224     }
225     ecore_main_loop_quit();
226     return;
227 }
228
229 static Eina_Bool timerCallback(void* /*data*/)
230 {
231     printf("result: %s\n", "failed");
232     ecore_main_loop_quit();
233     return EINA_FALSE;
234 }
235
236 int main(int argc, char* argv[])
237 {
238     UNHANDLED_EXCEPTION_HANDLER_BEGIN
239     {
240         int next_opt, opt_idx = 0;
241         int timeout = TIMEOUT_DEFAULT;
242         char applicationId[BUF_SIZE] = "";
243         char temp_arg[BUF_SIZE] = "";
244         char pid[6] = "";
245         char op = '\0';
246         bool isDebugMode = false;
247         bool dispHelp = false;
248         bool dispList = false;
249         Ecore_Timer* serviceTimer = NULL;
250
251         service_h serviceHandle = NULL;
252         int ret = SERVICE_ERROR_NONE;
253
254         program = argv[0];
255
256         static struct option long_options[] = {
257             { "help", no_argument, 0, 'h' },
258             { "list", no_argument, 0, 'l' },
259             { "start", required_argument, 0, 's' },
260             { "kill", required_argument, 0, 'k' },
261             { "is-running", required_argument, 0, 'r' },
262             { "debug", no_argument, 0, 'd' },
263             { "timeout", required_argument, 0, 't' },
264             { 0, 0, 0, 0 }
265         };
266
267         if (argv[1] == NULL) {
268             /* exit if any argument doesn't exist */
269             print_help(stdout, 0);
270             return -1;
271         }
272
273         if (ROOT_DEFAULT_UID == geteuid()) {
274             if (RETURN_ERROR == setuid(ROOT_DEFAULT_UID)) {
275                 perror("Fail to set uid");
276             }
277         }
278         if (ROOT_DEFAULT_GID == getegid()) {
279             if (RETURN_ERROR == setgid(ROOT_DEFAULT_GID)) {
280                 perror("Fail to set gid");
281             }
282         }
283
284         do {
285             next_opt = getopt_long(argc,
286                                    argv,
287                                    "hls:k:r:dt:v:c:i:m:",
288                                    long_options,
289                                    &opt_idx);
290
291             switch (next_opt) {
292             case 'h':
293                 if (!dispHelp) {
294                     print_help(stdout, 0);
295                     dispHelp = true;
296                 }
297                 break;
298
299             case 'l':
300                 if (dispList) {
301                     break;
302                 }
303                 if (!display_widget_info()) {
304                     printf("Fail to display the list of installed widgets");
305                     return -1;
306                 }
307                 dispList = true;
308                 break;
309
310             case 's':
311             case 'k':
312             case 'r':
313                 strncpy(temp_arg, optarg, BUF_SIZE);
314                 temp_arg[BUF_SIZE-1] = '\0';
315                 op = next_opt;
316                 break;
317
318             case 't':
319                 timeout = atoi(optarg);
320                 if (timeout < 0) {
321                     timeout = TIMEOUT_DEFAULT;
322                 }
323                 break;
324
325             case 'd':
326                 isDebugMode = true;
327                 break;
328
329             case -1:
330                 break;
331
332             default:
333                 print_help(stdout, 0);
334                 break;
335             }
336         } while (next_opt != -1);
337
338         if ((op == 's') || (op == 'k') || (op == 'r')) {
339             std::string temp;
340
341             if (NULL == g_dbConnection.get()) {
342                 Try {
343                     g_dbConnection.reset(new DBConnection());
344                     g_dbConnection->AttachDatabase();
345                 }
346                 Catch(DPL::DB::SqlConnection::Exception::Base) {
347                     LogDebug("Fail to connect DB");
348                     return FALSE;
349                 }
350             }
351             DPL::OptionalString normal_str = DPL::FromUTF8String(temp_arg);
352             WrtDB::NormalizeAndTrimSpaceString(normal_str);
353             std::string normal_arg = DPL::ToUTF8String(*normal_str);
354
355             WidgetDAOReadOnlyList widgetList =
356                 WrtDB::WidgetDAOReadOnly::getWidgetList();
357             FOREACH(dao, widgetList) {
358                 WrtDB::TizenAppId tizenAppId = (*dao)->getTzAppId();
359                 if (!strcmp(DPL::ToUTF8String(tizenAppId).c_str(),
360                             normal_arg.c_str()))
361                 {
362                     temp = DPL::ToUTF8String(tizenAppId);
363                     break;
364                 }
365             }
366             if (!temp.empty()) {
367                 strncpy(applicationId, temp.c_str(), BUF_SIZE);
368                 applicationId[BUF_SIZE-1] = '\0';
369             } else {
370                 printf("result: %s\n", "failed");
371                 return -1;
372             }
373         }
374
375         if (op == 's') {
376             if (strlen(applicationId) <= 0) {
377                 printf("result: %s\n", "failed");
378                 return -1;
379             }
380
381             // create service
382             ret = service_create(&serviceHandle);
383             if (SERVICE_ERROR_NONE != ret && NULL == serviceHandle) {
384                 printf("result: %s\n", "failed");
385                 return -1;
386             }
387
388             // set package
389             ret = service_set_package(serviceHandle, applicationId);
390             if (SERVICE_ERROR_NONE != ret) {
391                 printf("result: %s\n", "failed");
392                 service_destroy(serviceHandle);
393                 return -1;
394             }
395
396             if (true == isDebugMode) {
397                 // set debug mode
398                 ret = service_add_extra_data(serviceHandle, "debug", "true");
399                 if (SERVICE_ERROR_NONE != ret) {
400                     LogError("Fail to set debug mode [" << ret << "]");
401                     service_destroy(serviceHandle);
402                     return FALSE;
403                 }
404
405                 // set pid
406                 snprintf(pid, sizeof(pid), "%d", getpid());
407                 ret = service_add_extra_data(serviceHandle, "pid", pid);
408                 if (SERVICE_ERROR_NONE != ret) {
409                     LogError("Fail to set pid [" << ret << "]");
410                     service_destroy(serviceHandle);
411                     return FALSE;
412                 }
413
414                 ecore_init();
415                 serviceTimer = ecore_timer_add(timeout, timerCallback, NULL);
416                 ret = service_send_launch_request(serviceHandle,
417                                                   serviceReplyCallback,
418                                                   serviceTimer);
419             } else {
420                 ret = service_send_launch_request(serviceHandle, NULL, NULL);
421             }
422
423             if (SERVICE_ERROR_NONE != ret) {
424                 printf("result: %s\n", "");
425                 service_destroy(serviceHandle);
426                 return -1;
427             }
428
429             service_destroy(serviceHandle);
430
431             if (true == isDebugMode) {
432                 // wait response from callee
433                 ecore_main_loop_begin();
434                 return 0;
435             } else {
436                 // This text should be showed for IDE
437                 printf("result: %s\n", "launched");
438             }
439             return 0;
440         } else if (op == 'k') {
441             bool isRunning = false;
442
443             //checks whether the application is running
444             ret = app_manager_is_running(applicationId, &isRunning);
445             if (APP_MANAGER_ERROR_NONE != ret) {
446                 printf("result: %s\n", "failed");
447                 return -1;
448             }
449
450             if (true == isRunning) {
451                 // get app_context for running application
452                 // app_context must be released with app_context_destroy
453                 app_context_h appCtx = NULL;
454                 ret = app_manager_get_app_context(applicationId, &appCtx);
455                 if (APP_MANAGER_ERROR_NONE != ret) {
456                     printf("result: %s\n", "failed");
457                     return -1;
458                 }
459
460                 // terminate app_context_h
461                 ret = app_manager_terminate_app(appCtx);
462                 if (APP_MANAGER_ERROR_NONE != ret) {
463                     printf("result: %s\n", "failed");
464                     app_context_destroy(appCtx);
465                     return -1;
466                 } else {
467                     printf("result: %s\n", "killed");
468                     app_context_destroy(appCtx);
469                     return 0;
470                 }
471             } else {
472                 printf("result: %s\n", "App isn't running");
473                 return 0;
474             }
475         } else if (op == 'r') {
476             bool isRunning = false;
477             ret = app_manager_is_running(applicationId, &isRunning);
478
479             if (APP_MANAGER_ERROR_NONE != ret) {
480                 printf("result: %s\n", "failed");
481                 return -1;
482             }
483
484             if (true == isRunning) {
485                 printf("result: %s\n", "running");
486                 return 0;
487             } else {
488                 printf("result: %s\n", "not running");
489                 return -1;
490             }
491         }
492
493         return 0 ;
494     }
495     UNHANDLED_EXCEPTION_HANDLER_END
496 }
497