Add configuration for systemd.
[framework/security/security-server.git] / src / server2 / service / get-gid.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        get-gid.cpp
20  * @author      Jan Olszak (j.olszak@samsung.com)
21  * @version     1.0
22  * @brief       Implementation of api-get-gid service.
23  */
24
25 #include <sys/smack.h>
26 #include <grp.h>
27
28 #include <dpl/log/log.h>
29 #include <dpl/serialization.h>
30
31 #include <protocols.h>
32 #include <get-gid.h>
33 #include <security-server.h>
34
35 namespace SecurityServer {
36
37 GenericSocketService::ServiceDescriptionVector GetGidService::GetServiceDescription() {
38     ServiceDescription sd = {
39         "*",
40         0,
41         SERVICE_SOCKET_GET_GID
42     };
43     ServiceDescriptionVector v;
44     v.push_back(sd);
45     return v;
46 }
47
48 void GetGidService::accept(const AcceptEvent &event) {
49     LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock
50         << " ConnectionID.counter: " << event.connectionID.counter
51         << " ServiceID: " << event.interfaceID);
52 }
53
54 void GetGidService::write(const WriteEvent &event) {
55     LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
56         " Size: " << event.size << " Left: " << event.left);
57     if (event.left == 0)
58         m_serviceManager->Close(event.connectionID);
59 }
60
61
62 /*
63  * Searches for group ID by given group name
64  */
65 int GetGidService::setGid(std::string& obj)
66 {
67     int ret = 0;
68     struct group *grpbuf = NULL;
69     struct group grp;
70     std::vector<char> buf;
71
72     /*
73      * The maximum needed size for buf can be found using sysconf(3)
74      * with the argument _SC_GETGR_R_SIZE_MAX. If _SC_GETGR_R_SIZE_MAX is not
75      * returned we set max_buf_size to 1024 bytes. Enough to store few groups.
76      */
77     long int maxBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
78     if (maxBufSize == -1)
79         maxBufSize = 1024;
80
81
82     /*
83      * There can be some corner cases when for example user is assigned to a
84      * lot of groups. In that case if buffer is to small getgrnam_r will
85      * return ERANGE error. Solution could be calling getgrnam_r with bigger
86      * buffer until it's big enough.
87      */
88     do {
89         try{
90             buf.resize(maxBufSize);
91         }catch(std::bad_alloc&) {
92             ret = SECURITY_SERVER_API_ERROR_OUT_OF_MEMORY;
93             LogError("Out Of Memory");
94             return ret;
95         }
96         maxBufSize *= 2;
97     } while ((ret = getgrnam_r(obj.c_str(), &grp, &(buf[0]), buf.size(), &grpbuf)) == ERANGE);
98
99     // Check for errors:
100     if (ret != 0){
101         ret = SECURITY_SERVER_API_ERROR_SERVER_ERROR;
102         LogError("getgrnam_r failed with error: " << strerror(errno));
103         return ret;
104
105     } else if (grpbuf == NULL) {
106         ret = SECURITY_SERVER_API_ERROR_NO_SUCH_OBJECT;
107         LogError("Cannot find gid for group: " << obj);
108         return ret;
109     }
110
111     m_gid = grpbuf->gr_gid;
112
113     return ret;
114 }
115
116
117 bool GetGidService::readOne(const ConnectionID &conn, SocketBuffer &buffer) {
118     LogDebug("Iteration begin");
119     std::string objectName;
120     int retCode = SECURITY_SERVER_API_ERROR_SERVER_ERROR;
121
122     if (!buffer.Ready()) {
123         return false;
124     }
125
126     // Get objects name:
127     Try {
128         SecurityServer::Deserialization des;
129         des.Deserialize(buffer, objectName);
130      } Catch (SocketBuffer::Exception::Base) {
131         LogDebug("Broken protocol. Closing socket.");
132         m_serviceManager->Close(conn);
133         return false;
134     }
135
136     // Get GID
137     retCode = setGid(objectName);
138
139     // Send the result
140     SecurityServer::Serialization ser;
141     SocketBuffer sendBuffer;
142     ser.Serialize(sendBuffer, retCode);
143     ser.Serialize(sendBuffer, m_gid);
144     m_serviceManager->Write(conn, sendBuffer.Pop());
145     return true;
146 }
147
148 void GetGidService::read(const ReadEvent &event) {
149     LogDebug("Read event for counter: " << event.connectionID.counter);
150     auto &buffer = m_socketBufferMap[event.connectionID.counter];
151     buffer.Push(event.rawBuffer);
152
153     // We can get several requests in one package.
154     // Extract and process them all
155     while(readOne(event.connectionID, buffer));
156 }
157
158 void GetGidService::close(const CloseEvent &event) {
159     LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
160     m_socketBufferMap.erase(event.connectionID.counter);
161 }
162
163 void GetGidService::error(const ErrorEvent &event) {
164     LogDebug("ErrorEvent. ConnectionID: " << event.connectionID.sock);
165     m_serviceManager->Close(event.connectionID);
166 }
167
168 } // namespace SecurityServer
169