1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/socket/unix_domain_server_socket_posix.h" 6 7 #include <errno.h> 8 #include <sys/socket.h> 9 #include <sys/un.h> 10 #include <unistd.h> 11 12 #include "base/logging.h" 13 #include "net/base/net_errors.h" 14 #include "net/socket/socket_libevent.h" 15 #include "net/socket/unix_domain_client_socket_posix.h" 16 17 namespace net { 18 19 namespace { 20 21 // Intended for use as SetterCallbacks in Accept() helper methods. 22 void SetStreamSocket(scoped_ptr<StreamSocket>* socket, 23 scoped_ptr<SocketLibevent> accepted_socket) { 24 socket->reset(new UnixDomainClientSocket(accepted_socket.Pass())); 25 } 26 27 void SetSocketDescriptor(SocketDescriptor* socket, 28 scoped_ptr<SocketLibevent> accepted_socket) { 29 *socket = accepted_socket->ReleaseConnectedSocket(); 30 } 31 32 } // anonymous namespace 33 34 UnixDomainServerSocket::UnixDomainServerSocket( 35 const AuthCallback& auth_callback, 36 bool use_abstract_namespace) 37 : auth_callback_(auth_callback), 38 use_abstract_namespace_(use_abstract_namespace) { 39 DCHECK(!auth_callback_.is_null()); 40 } 41 42 UnixDomainServerSocket::~UnixDomainServerSocket() { 43 } 44 45 // static 46 bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket, 47 Credentials* credentials) { 48 #if defined(OS_LINUX) || defined(OS_ANDROID) 49 struct ucred user_cred; 50 socklen_t len = sizeof(user_cred); 51 if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0) 52 return false; 53 credentials->process_id = user_cred.pid; 54 credentials->user_id = user_cred.uid; 55 credentials->group_id = user_cred.gid; 56 return true; 57 #else 58 return getpeereid( 59 socket, &credentials->user_id, &credentials->group_id) == 0; 60 #endif 61 } 62 63 int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) { 64 NOTIMPLEMENTED(); 65 return ERR_NOT_IMPLEMENTED; 66 } 67 68 int UnixDomainServerSocket::ListenWithAddressAndPort( 69 const std::string& unix_domain_path, 70 int port_unused, 71 int backlog) { 72 DCHECK(!listen_socket_); 73 74 SockaddrStorage address; 75 if (!UnixDomainClientSocket::FillAddress(unix_domain_path, 76 use_abstract_namespace_, 77 &address)) { 78 return ERR_ADDRESS_INVALID; 79 } 80 81 scoped_ptr<SocketLibevent> socket(new SocketLibevent); 82 int rv = socket->Open(AF_UNIX); 83 DCHECK_NE(ERR_IO_PENDING, rv); 84 if (rv != OK) 85 return rv; 86 87 rv = socket->Bind(address); 88 DCHECK_NE(ERR_IO_PENDING, rv); 89 if (rv != OK) { 90 PLOG(ERROR) 91 << "Could not bind unix domain socket to " << unix_domain_path 92 << (use_abstract_namespace_ ? " (with abstract namespace)" : ""); 93 return rv; 94 } 95 96 rv = socket->Listen(backlog); 97 DCHECK_NE(ERR_IO_PENDING, rv); 98 if (rv != OK) 99 return rv; 100 101 listen_socket_.swap(socket); 102 return rv; 103 } 104 105 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const { 106 NOTIMPLEMENTED(); 107 return ERR_NOT_IMPLEMENTED; 108 } 109 110 int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket, 111 const CompletionCallback& callback) { 112 DCHECK(socket); 113 114 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket); 115 return DoAccept(setter_callback, callback); 116 } 117 118 int UnixDomainServerSocket::AcceptSocketDescriptor( 119 SocketDescriptor* socket, 120 const CompletionCallback& callback) { 121 DCHECK(socket); 122 123 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket); 124 return DoAccept(setter_callback, callback); 125 } 126 127 int UnixDomainServerSocket::DoAccept(const SetterCallback& setter_callback, 128 const CompletionCallback& callback) { 129 DCHECK(!setter_callback.is_null()); 130 DCHECK(!callback.is_null()); 131 DCHECK(listen_socket_); 132 DCHECK(!accept_socket_); 133 134 while (true) { 135 int rv = listen_socket_->Accept( 136 &accept_socket_, 137 base::Bind(&UnixDomainServerSocket::AcceptCompleted, 138 base::Unretained(this), 139 setter_callback, 140 callback)); 141 if (rv != OK) 142 return rv; 143 if (AuthenticateAndGetStreamSocket(setter_callback)) 144 return OK; 145 // Accept another socket because authentication error should be transparent 146 // to the caller. 147 } 148 } 149 150 void UnixDomainServerSocket::AcceptCompleted( 151 const SetterCallback& setter_callback, 152 const CompletionCallback& callback, 153 int rv) { 154 if (rv != OK) { 155 callback.Run(rv); 156 return; 157 } 158 159 if (AuthenticateAndGetStreamSocket(setter_callback)) { 160 callback.Run(OK); 161 return; 162 } 163 164 // Accept another socket because authentication error should be transparent 165 // to the caller. 166 rv = DoAccept(setter_callback, callback); 167 if (rv != ERR_IO_PENDING) 168 callback.Run(rv); 169 } 170 171 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket( 172 const SetterCallback& setter_callback) { 173 DCHECK(accept_socket_); 174 175 Credentials credentials; 176 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) || 177 !auth_callback_.Run(credentials)) { 178 accept_socket_.reset(); 179 return false; 180 } 181 182 setter_callback.Run(accept_socket_.Pass()); 183 return true; 184 } 185 186 } // namespace net 187