Resolve TOCTOU
[platform/core/security/vist.git] / src / vist / rmi / impl / socket.cpp
1 /*
2  *  Copyright (c) 2018-present 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 #include "socket.hpp"
18
19 #include <vist/logger.hpp>
20
21 #include <fstream>
22 #include <iostream>
23 #include <fcntl.h>
24
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/un.h>
28
29 namespace vist {
30 namespace rmi {
31 namespace impl {
32
33 namespace {
34
35 void set_cloexec(int fd)
36 {
37         if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
38                 THROW(ErrCode::RuntimeError) << "Failed to set CLOSEXEC.";
39 }
40
41 } // anonymous namespace
42
43 Socket::Socket(int fd) noexcept : fd(fd)
44 {
45 }
46
47 Socket::Socket(const std::string& path)
48 {
49         if (path.size() >= sizeof(::sockaddr_un::sun_path))
50                 THROW(ErrCode::LogicError) << "Socket path size is wrong.";
51
52         int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
53         if (fd == -1)
54                 THROW(ErrCode::RuntimeError) << "Failed to create socket.";
55
56         set_cloexec(fd);
57
58         ::sockaddr_un addr;
59         addr.sun_family = AF_UNIX;
60         ::strncpy(addr.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path) - 1);
61         addr.sun_path[sizeof(sockaddr_un::sun_path) - 1] = '\0';
62
63         if (addr.sun_path[0] == '@') {
64                 addr.sun_path[0] = '\0';
65         } else {
66                 errno = 0;
67                 if (::unlink(path.c_str()) == -1)
68                         WARN(VIST) << "Failed to remove exist socket: " << errno;
69         }
70
71         if (::bind(fd, reinterpret_cast<::sockaddr*>(&addr), sizeof(::sockaddr_un)) == -1) {
72                 ::close(fd);
73                 THROW(ErrCode::RuntimeError) << "Failed to bind.";
74         }
75
76         if (::listen(fd, MAX_BACKLOG_SIZE) == -1) {
77                 ::close(fd);
78                 THROW(ErrCode::RuntimeError) << "Failed to liten.";
79         }
80
81         this->fd = fd;
82
83         DEBUG(VIST) << "Socket is created: " << path << ", and is listening.. fd[" << fd << "]";
84 }
85
86 Socket::Socket(Socket&& that) : fd(that.fd)
87 {
88         that.fd = -1;
89 }
90
91 Socket& Socket::operator=(Socket&& that)
92 {
93         if (this == &that)
94                 return *this;
95
96         this->fd = that.fd;
97         that.fd = -1;
98
99         return *this;
100 }
101
102 Socket::~Socket(void)
103 {
104         if (fd != -1)
105                 ::close(fd);
106 }
107
108 Socket Socket::accept(void) const
109 {
110         errno = 0;
111         int fd = ::accept(this->fd, nullptr, nullptr);
112         if (fd == -1)
113                 THROW(ErrCode::RuntimeError) << "Failed to accept: " << errno;
114
115         set_cloexec(fd);
116
117         return Socket(fd);
118 }
119
120 Socket Socket::connect(const std::string& path)
121 {
122         if (path.size() >= sizeof(::sockaddr_un::sun_path))
123                 THROW(ErrCode::LogicError) << "Socket path size is wrong.";
124
125         int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
126         if (fd == -1)
127                 THROW(ErrCode::RuntimeError) << "Failed to create socket.";
128
129         set_cloexec(fd);
130
131         ::sockaddr_un addr;
132         addr.sun_family = AF_UNIX;
133         ::strncpy(addr.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path) - 1);
134         addr.sun_path[sizeof(sockaddr_un::sun_path) - 1] = '\0';
135
136         if (addr.sun_path[0] == '@')
137                 addr.sun_path[0] = '\0';
138
139         DEBUG(VIST) << "Start to connect: " << path;
140         errno = 0;
141         if (::connect(fd, reinterpret_cast<::sockaddr*>(&addr), sizeof(sockaddr_un)) == -1) {
142                 ::close(fd);
143                 ERROR(VIST) << "Failed to connect to: " << path;
144                 THROW(ErrCode::RuntimeError) << "Failed to connect to: " << path
145                                                                          << ", with: " << errno;
146         }
147
148         return Socket(fd);
149 }
150
151 int Socket::getFd(void) const noexcept
152 {
153         return this->fd;
154 }
155
156 } // namespace impl
157 } // namespace rmi
158 } // namespace vist