6a4527309de2e981b25a0fc26e51fa4accf9dc0c
[platform/core/security/security-manager.git] / src / server / service / cookie.cpp
1 /*
2  *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Bumjin Im <bj.im@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18 /*
19  * @file        cookie.cpp
20  * @author      Pawel Polawski (p.polawski@partner.samsung.com)
21  * @version     1.0
22  * @brief       This function contain implementation of CookieService
23  */
24
25 #include <memory>
26 #include <dpl/log/log.h>
27 #include <dpl/serialization.h>
28 #include <protocols.h>
29 #include <cookie-common.h>
30 #include <security-server.h>
31 #include <cookie.h>
32 #include <smack-check.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/smack.h>
36 #include <linux/limits.h>
37
38 //interfaces ID
39 const int INTERFACE_GET = 0;
40 const int INTERFACE_CHECK = 1;
41
42 namespace SecurityServer {
43
44 GenericSocketService::ServiceDescriptionVector CookieService::GetServiceDescription() {
45     return ServiceDescriptionVector {
46         {SERVICE_SOCKET_COOKIE_GET,       "*",   INTERFACE_GET },
47         {SERVICE_SOCKET_COOKIE_CHECK,     "security-server::api-cookie-check", INTERFACE_CHECK}
48     };
49  }
50
51 void CookieService::accept(const AcceptEvent &event) {
52     LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock
53         << " ConnectionID.counter: " << event.connectionID.counter
54         << " ServiceID: " << event.interfaceID);
55     auto &info = m_connectionInfoMap[event.connectionID.counter];
56     info.interfaceID = event.interfaceID;
57 }
58
59 void CookieService::write(const WriteEvent &event) {
60     LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
61         " Size: " << event.size << " Left: " << event.left);
62     if (event.left == 0)
63         m_serviceManager->Close(event.connectionID);
64 }
65
66 void CookieService::process(const ReadEvent &event) {
67     LogDebug("Read event for counter: " << event.connectionID.counter);
68     auto &info = m_connectionInfoMap[event.connectionID.counter];
69     info.buffer.Push(event.rawBuffer);
70
71     // We can get several requests in one package.
72     // Extract and process them all
73     while(processOne(event.connectionID, info.buffer, info.interfaceID));
74 }
75
76 void CookieService::close(const CloseEvent &event) {
77     LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
78     m_connectionInfoMap.erase(event.connectionID.counter);
79 }
80
81 bool CookieService::processOne(const ConnectionID &conn, MessageBuffer &buffer, InterfaceID interfaceID)
82 {
83     LogDebug("Iteration begin");
84     MessageBuffer send, recv;
85     CookieCall msgType;
86     bool removeGarbage = false;
87
88     //waiting for all data
89     if (!buffer.Ready()) {
90         return false;
91     }
92
93     //receive data from buffer and check MSG_ID
94     Try {
95         int msgTypeInt;
96         Deserialization::Deserialize(buffer, msgTypeInt);  //receive MSG_ID
97         msgType = static_cast<CookieCall>(msgTypeInt);
98     } Catch (MessageBuffer::Exception::Base) {
99         LogDebug("Broken protocol. Closing socket.");
100         m_serviceManager->Close(conn);
101         return false;
102     }
103
104     bool retval = false;
105
106     //use received data
107     if (interfaceID == INTERFACE_GET) {
108         switch(msgType) {
109         case CookieCall::GET_COOKIE:
110             LogDebug("Entering get-cookie server side handler");
111             retval = cookieRequest(send, conn.sock);
112             removeGarbage = true;
113             break;
114
115         default:
116             LogDebug("Error, unknown function called by client");
117             retval = false;
118             break;
119         };
120     } else if (interfaceID == INTERFACE_CHECK) {
121         switch(msgType) {
122         case CookieCall::CHECK_PID:
123             LogDebug("Entering pid-by-cookie server side handler");
124             retval = pidByCookieRequest(buffer, send);
125             break;
126
127         case CookieCall::CHECK_SMACKLABEL:
128             LogDebug("Entering smacklabel-by-cookie server side handler");
129             retval = smackLabelByCookieRequest(buffer, send);
130             break;
131
132         case CookieCall::CHECK_PRIVILEGE_GID:
133             LogDebug("Entering check-privilege-by-cookie-gid server side handler");
134             retval = privilegeByCookieGidRequest(buffer, send);
135             break;
136
137         case CookieCall::CHECK_PRIVILEGE:
138             LogDebug("Entering check-privilege-by-cookie side handler");
139             retval = privilegeByCookieRequest(buffer, send);
140             break;
141
142         case CookieCall::CHECK_UID:
143             LogDebug("Entering get-uid-by-cookie side handler");
144             retval = uidByCookieRequest(buffer, send);
145             break;
146
147         case CookieCall::CHECK_GID:
148             LogDebug("Entering get-gid-by-cookie side handler");
149             retval = gidByCookieRequest(buffer, send);
150             break;
151
152         default:
153             LogDebug("Error, unknown function called by client");
154             retval = false;
155             break;
156         };
157     } else {
158         LogDebug("Error, wrong interface");
159         retval = false;
160     }
161
162     if (retval) {
163         //send response
164         m_serviceManager->Write(conn, send.Pop());
165     } else {
166         LogDebug("Closing socket because of error");
167         m_serviceManager->Close(conn);
168     }
169
170     // Each time you add one cookie check 2 others.
171     if (removeGarbage)
172         m_cookieJar.GarbageCollector(2);
173
174     return retval;
175 }
176
177 bool CookieService::cookieRequest(MessageBuffer &send, int socket)
178 {
179     struct ucred cr;
180     unsigned len = sizeof(cr);
181
182     if (0 != getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &cr, &len))
183         return false;
184
185     const Cookie *generatedCookie = m_cookieJar.GenerateCookie(cr.pid);
186
187     if (generatedCookie == NULL) {
188         //unable to create cookie
189         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_UNKNOWN);
190         return true;
191     }
192
193     //checking if binary path match created / found cookie
194     char path[PATH_MAX];
195     int ret = getPidPath(path, PATH_MAX, cr.pid);
196
197     if (ret < 0) {
198         LogError("Unable to check process binary path");
199         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_UNKNOWN);
200     } else {
201         if (generatedCookie->binaryPath.compare(path)) {
202             LogDebug("Found cookie but no match in bin path");
203             Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_UNKNOWN);
204         } else {
205             Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
206             Serialization::Serialize(send, generatedCookie->cookieId);
207         }
208     }
209
210     return true;
211 }
212
213 bool CookieService::pidByCookieRequest(MessageBuffer &buffer, MessageBuffer &send)
214 {
215     std::vector<char> cookieKey;
216
217     Try {
218         Deserialization::Deserialize(buffer, cookieKey);
219     } Catch (MessageBuffer::Exception::Base) {
220         LogDebug("Broken protocol. Closing socket.");
221         return false;
222     }
223
224     Cookie searchPattern;
225     searchPattern.cookieId = cookieKey;
226
227     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
228
229     if (searchResult != NULL) {
230         Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
231         Serialization::Serialize(send, (int)searchResult->pid);
232     } else {
233         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_NO_SUCH_COOKIE);
234     }
235
236     return true;
237 }
238
239 bool CookieService::smackLabelByCookieRequest(MessageBuffer &buffer, MessageBuffer &send)
240 {
241     std::vector<char> cookieKey;
242
243     Try {
244         Deserialization::Deserialize(buffer, cookieKey);
245     } Catch (MessageBuffer::Exception::Base) {
246         LogDebug("Broken protocol. Closing socket.");
247         return false;
248     }
249
250     Cookie searchPattern;
251     searchPattern.cookieId = cookieKey;
252
253     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
254
255     if (searchResult != NULL) {
256         Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
257         Serialization::Serialize(send, searchResult->smackLabel);
258     } else {
259         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_NO_SUCH_COOKIE);
260     }
261
262     return true;
263 }
264
265 bool CookieService::privilegeByCookieGidRequest(MessageBuffer &buffer, MessageBuffer &send)
266 {
267     std::vector<char> cookieKey;
268     int gid;
269
270     Try {
271         Deserialization::Deserialize(buffer, cookieKey);
272         Deserialization::Deserialize(buffer, gid);
273     } Catch (MessageBuffer::Exception::Base) {
274         LogDebug("Broken protocol. Closing socket.");
275         return false;
276     }
277
278     Cookie searchPattern;
279     searchPattern.cookieId = cookieKey;
280
281     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
282
283     if (searchResult != NULL)
284         //search for specified GID on permissions list
285         for (size_t i = 0; i < searchResult->permissions.size(); i++)
286             if (searchResult->permissions[i] == gid) {
287                 Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
288                 return true;
289             }
290
291     Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_ACCESS_DENIED);
292
293     return true;
294 }
295
296 bool CookieService::privilegeByCookieRequest(MessageBuffer &buffer, MessageBuffer &send)
297 {
298     std::vector<char> cookieKey;
299     std::string subject;
300     std::string object;
301     std::string access;
302
303     Try {
304         Deserialization::Deserialize(buffer, cookieKey);
305         Deserialization::Deserialize(buffer, object);
306         Deserialization::Deserialize(buffer, access);
307     } Catch (MessageBuffer::Exception::Base) {
308         LogDebug("Broken protocol. Closing socket.");
309         return false;
310     }
311
312     Cookie searchPattern;
313     searchPattern.cookieId = cookieKey;
314
315     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
316
317     if (searchResult != NULL) {
318         if (!smack_check()) {
319             Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
320         } else {
321             subject = searchResult->smackLabel;
322             int retval;
323
324             if ((retval = smack_have_access(subject.c_str(), object.c_str(), access.c_str())) == 1)
325                 Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
326             else {
327                 Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_ACCESS_DENIED);
328                 LogSmackAudit("SS_SMACK: "
329                     << " subject=" << subject
330                     << ", object=" << object
331                     << ", access=" << access
332                     << ", result=" << retval);
333             }
334         }
335     } else {
336         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_NO_SUCH_COOKIE);
337     }
338
339     return true;
340 }
341
342 bool CookieService::uidByCookieRequest(MessageBuffer &buffer, MessageBuffer &send)
343 {
344     std::vector<char> cookieKey;
345
346     Try {
347         Deserialization::Deserialize(buffer, cookieKey);
348     } Catch (MessageBuffer::Exception::Base) {
349         LogDebug("Broken protocol. Closing socket.");
350         return false;
351     }
352
353     Cookie searchPattern;
354     searchPattern.cookieId = cookieKey;
355
356     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
357
358     if (searchResult != NULL) {
359         Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
360         Serialization::Serialize(send, (int)searchResult->uid);
361     } else {
362         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_NO_SUCH_COOKIE);
363     }
364
365     return true;
366 }
367
368 bool CookieService::gidByCookieRequest(MessageBuffer &buffer, MessageBuffer &send)
369 {
370     std::vector<char> cookieKey;
371
372     Try {
373         Deserialization::Deserialize(buffer, cookieKey);
374     } Catch (MessageBuffer::Exception::Base) {
375         LogDebug("Broken protocol. Closing socket.");
376         return false;
377     }
378
379     Cookie searchPattern;
380     searchPattern.cookieId = cookieKey;
381
382     const Cookie *searchResult = m_cookieJar.SearchCookie(searchPattern, CompareType::COOKIE_ID);
383
384     if (searchResult != NULL) {
385         Serialization::Serialize(send, (int)SECURITY_SERVER_API_SUCCESS);
386         Serialization::Serialize(send, (int)searchResult->gid);
387     } else {
388         Serialization::Serialize(send, (int)SECURITY_SERVER_API_ERROR_NO_SUCH_COOKIE);
389     }
390
391     return true;
392 }
393
394 } // namespace SecurityServer
395