bffd8ea46532c0c110da464bd97eaa79b3a39b00
[apps/livebox/data-provider-master.git] / src / shortcut_service.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <stdio.h>
17
18 #include <Eina.h>
19
20 #include <dlog.h>
21 #if defined(HAVE_LIVEBOX)
22 #include <livebox-errno.h>
23 #else
24 #include "lite-errno.h"
25 #endif
26 #include <packet.h>
27
28 #include <Eina.h>
29 #include <sys/smack.h>
30
31 #include <security-server.h>
32 #include <shortcut.h>
33
34 #include "service_common.h"
35 #include "debug.h"
36 #include "util.h"
37 #include "conf.h"
38
39 static struct info {
40         Eina_List *context_list;
41         struct service_context *svc_ctx;
42 } s_info = {
43         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
44         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
45 };
46
47 struct context {
48         struct tcb *tcb;
49         double seq;
50 };
51
52 /*!
53  * SERVICE THREAD
54  */
55 static inline int put_reply_context(struct tcb *tcb, double seq)
56 {
57         struct context *ctx;
58
59         ctx = malloc(sizeof(*ctx));
60         if (!ctx) {
61                 ErrPrint("Heap: %s\n", strerror(errno));
62                 return -ENOMEM;
63         }
64
65         ctx->tcb = tcb;
66         ctx->seq = seq; /* Could we this sequence value is uniq? */
67
68         s_info.context_list = eina_list_append(s_info.context_list, ctx);
69         return 0;
70 }
71
72 /*!
73  * SERVICE THREAD
74  */
75 static inline struct tcb *get_reply_context(double seq)
76 {
77         Eina_List *l;
78         Eina_List *n;
79         struct context *ctx;
80         struct tcb *tcb;
81
82         tcb = NULL;
83         EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
84                 if (ctx->seq != seq) {
85                         continue;
86                 }
87
88                 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
89                 tcb = ctx->tcb;
90                 DbgFree(ctx);
91                 break;
92         }
93
94         return tcb;
95 }
96
97 static void send_reply_packet(struct tcb *tcb, struct packet *packet, int ret)
98 {
99         struct packet *reply_packet;
100
101         reply_packet = packet_create_reply(packet, "i", ret);
102         if (!reply_packet) {
103                 ErrPrint("Failed to create a packet\n");
104                 return;
105         }
106
107         if (service_common_unicast_packet(tcb, reply_packet) < 0) {
108                 ErrPrint("Unable to send reply packet\n");
109         }
110
111         packet_destroy(reply_packet);
112 }
113
114 /*!
115  * SERVICE THREAD
116  */
117 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
118 {
119         const char *command;
120         int ret;
121
122         if (!packet) {
123                 DbgPrint("TCB: %p is terminated (NIL packet)\n", tcb);
124                 return 0;
125         }
126
127         command = packet_command(packet);
128         if (!command) {
129                 ErrPrint("Invalid command\n");
130                 return -EINVAL;
131         }
132
133         switch (packet_type(packet)) {
134         case PACKET_REQ:
135
136                 /* Need to send reply packet */
137                 DbgPrint("%p REQ: Command: [%s]\n", tcb, command);
138                 if (!strcmp(command, "add_livebox") || !strcmp(command, "rm_livebox")) {
139                         ret = security_server_check_privilege_by_sockfd(tcb_fd(tcb), "data-provider-master::shortcut.livebox", "w");
140                         if (ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED) {
141                                 ErrPrint("SMACK:Access denied\n");
142                                 send_reply_packet(tcb, packet, SHORTCUT_ERROR_PERMISSION);
143                                 break;
144                         }
145
146                 } else if (!strcmp(command, "add_shortcut") || !strcmp(command, "rm_shortcut")) {
147                         ret = security_server_check_privilege_by_sockfd(tcb_fd(tcb), "data-provider-master::shortcut.shortcut", "w");
148                         if (ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED) {
149                                 ErrPrint("SMACK:Access denied\n");
150                                 send_reply_packet(tcb, packet, SHORTCUT_ERROR_PERMISSION);
151                                 break;
152                         }
153                 }
154
155                 if (service_common_multicast_packet(tcb, packet, TCB_CLIENT_TYPE_SERVICE) < 0) {
156                         ErrPrint("Unable to send service request packet\n");
157                 } else {
158                         (void)put_reply_context(tcb, packet_seq(packet));
159                 }
160                 break;
161         case PACKET_REQ_NOACK:
162                 /* Doesn't need to send reply packet */
163                 DbgPrint("%p REQ_NOACK: Command: [%s]\n", tcb, command);
164                 if (!strcmp(command, "service_register")) {
165                         tcb_client_type_set(tcb, TCB_CLIENT_TYPE_SERVICE);
166                         break;
167                 }
168
169                 if (service_common_multicast_packet(tcb, packet, TCB_CLIENT_TYPE_SERVICE) < 0) {
170                         ErrPrint("Unable to send service reuqest packet\n");
171                 }
172                 break;
173         case PACKET_ACK:
174                 /* Okay, client(or app) send a reply packet to us. */
175                 DbgPrint("%p ACK: Command: [%s]\n", tcb, command);
176                 tcb = get_reply_context(packet_seq(packet));
177                 if (!tcb) {
178                         ErrPrint("There is no proper context\n");
179                         break;
180                 }
181
182                 if (tcb_is_valid(s_info.svc_ctx, tcb) < 0) {
183                         ErrPrint("TCB is not valid (already disconnected?)\n");
184                         break;
185                 }
186
187                 if (service_common_unicast_packet(tcb, packet) < 0) {
188                         ErrPrint("Unable to send reply packet\n");
189                 }
190                 break;
191         default:
192                 ErrPrint("Packet type is not valid[%s]\n", command);
193                 return -EINVAL;
194         }
195
196         /*!
197          * return value has no meanning,
198          * it will be printed by dlogutil.
199          */
200         return 0;
201 }
202
203
204 /*!
205  * MAIN THREAD
206  * Do not try to do anyother operation in these functions
207  */
208
209 HAPI int shortcut_service_init(void)
210 {
211         if (s_info.svc_ctx) {
212                 ErrPrint("Already initialized\n");
213                 return LB_STATUS_ERROR_ALREADY;
214         }
215
216         s_info.svc_ctx = service_common_create(SHORTCUT_SOCKET, service_thread_main, NULL);
217         if (!s_info.svc_ctx) {
218                 ErrPrint("Unable to activate service thread\n");
219                 return LB_STATUS_ERROR_FAULT;
220         }
221
222         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), SHORTCUT_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
223                 if (errno != EOPNOTSUPP) {
224                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
225                         service_common_destroy(s_info.svc_ctx);
226                         s_info.svc_ctx = NULL;
227                         return LB_STATUS_ERROR_FAULT;
228                 }
229         }
230
231         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), SHORTCUT_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
232                 if (errno != EOPNOTSUPP) {
233                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
234                         service_common_destroy(s_info.svc_ctx);
235                         s_info.svc_ctx = NULL;
236                         return LB_STATUS_ERROR_FAULT;
237                 }
238         }
239
240         DbgPrint("Successfully initiated\n");
241         return LB_STATUS_SUCCESS;
242 }
243
244 HAPI int shortcut_service_fini(void)
245 {
246         if (!s_info.svc_ctx) {
247                 return LB_STATUS_ERROR_INVALID;
248         }
249
250         service_common_destroy(s_info.svc_ctx);
251         s_info.svc_ctx = NULL;
252         DbgPrint("Successfully Finalized\n");
253         return LB_STATUS_SUCCESS;
254 }
255
256 /* End of a file */