PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/chromium/net/socket/unix_domain_socket_posix.cc

https://gitlab.com/f3822/qtwebengine-chromium
C++ | 196 lines | 156 code | 26 blank | 14 comment | 22 complexity | 02d6b9f7d97be9b3a5f6469757a8e538 MD5 | raw file
  1. // Copyright (c) 2012 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. #include "net/socket/unix_domain_socket_posix.h"
  5. #include <cstring>
  6. #include <string>
  7. #include <errno.h>
  8. #include <sys/socket.h>
  9. #include <sys/stat.h>
  10. #include <sys/types.h>
  11. #include <sys/un.h>
  12. #include <unistd.h>
  13. #include "base/bind.h"
  14. #include "base/callback.h"
  15. #include "base/posix/eintr_wrapper.h"
  16. #include "base/threading/platform_thread.h"
  17. #include "build/build_config.h"
  18. #include "net/base/net_errors.h"
  19. #include "net/base/net_util.h"
  20. #include "net/socket/socket_descriptor.h"
  21. namespace net {
  22. namespace {
  23. bool NoAuthenticationCallback(uid_t, gid_t) {
  24. return true;
  25. }
  26. bool GetPeerIds(int socket, uid_t* user_id, gid_t* group_id) {
  27. #if defined(OS_LINUX) || defined(OS_ANDROID)
  28. struct ucred user_cred;
  29. socklen_t len = sizeof(user_cred);
  30. if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) == -1)
  31. return false;
  32. *user_id = user_cred.uid;
  33. *group_id = user_cred.gid;
  34. #else
  35. if (getpeereid(socket, user_id, group_id) == -1)
  36. return false;
  37. #endif
  38. return true;
  39. }
  40. } // namespace
  41. // static
  42. UnixDomainSocket::AuthCallback UnixDomainSocket::NoAuthentication() {
  43. return base::Bind(NoAuthenticationCallback);
  44. }
  45. // static
  46. scoped_ptr<UnixDomainSocket> UnixDomainSocket::CreateAndListenInternal(
  47. const std::string& path,
  48. const std::string& fallback_path,
  49. StreamListenSocket::Delegate* del,
  50. const AuthCallback& auth_callback,
  51. bool use_abstract_namespace) {
  52. SocketDescriptor s = CreateAndBind(path, use_abstract_namespace);
  53. if (s == kInvalidSocket && !fallback_path.empty())
  54. s = CreateAndBind(fallback_path, use_abstract_namespace);
  55. if (s == kInvalidSocket)
  56. return scoped_ptr<UnixDomainSocket>();
  57. scoped_ptr<UnixDomainSocket> sock(
  58. new UnixDomainSocket(s, del, auth_callback));
  59. sock->Listen();
  60. return sock.Pass();
  61. }
  62. // static
  63. scoped_ptr<UnixDomainSocket> UnixDomainSocket::CreateAndListen(
  64. const std::string& path,
  65. StreamListenSocket::Delegate* del,
  66. const AuthCallback& auth_callback) {
  67. return CreateAndListenInternal(path, "", del, auth_callback, false);
  68. }
  69. #if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
  70. // static
  71. scoped_ptr<UnixDomainSocket>
  72. UnixDomainSocket::CreateAndListenWithAbstractNamespace(
  73. const std::string& path,
  74. const std::string& fallback_path,
  75. StreamListenSocket::Delegate* del,
  76. const AuthCallback& auth_callback) {
  77. return
  78. CreateAndListenInternal(path, fallback_path, del, auth_callback, true);
  79. }
  80. #endif
  81. UnixDomainSocket::UnixDomainSocket(
  82. SocketDescriptor s,
  83. StreamListenSocket::Delegate* del,
  84. const AuthCallback& auth_callback)
  85. : StreamListenSocket(s, del),
  86. auth_callback_(auth_callback) {}
  87. UnixDomainSocket::~UnixDomainSocket() {}
  88. // static
  89. SocketDescriptor UnixDomainSocket::CreateAndBind(const std::string& path,
  90. bool use_abstract_namespace) {
  91. sockaddr_un addr;
  92. static const size_t kPathMax = sizeof(addr.sun_path);
  93. if (use_abstract_namespace + path.size() + 1 /* '\0' */ > kPathMax)
  94. return kInvalidSocket;
  95. const SocketDescriptor s = CreatePlatformSocket(PF_UNIX, SOCK_STREAM, 0);
  96. if (s == kInvalidSocket)
  97. return kInvalidSocket;
  98. memset(&addr, 0, sizeof(addr));
  99. addr.sun_family = AF_UNIX;
  100. socklen_t addr_len;
  101. if (use_abstract_namespace) {
  102. // Convert the path given into abstract socket name. It must start with
  103. // the '\0' character, so we are adding it. |addr_len| must specify the
  104. // length of the structure exactly, as potentially the socket name may
  105. // have '\0' characters embedded (although we don't support this).
  106. // Note that addr.sun_path is already zero initialized.
  107. memcpy(addr.sun_path + 1, path.c_str(), path.size());
  108. addr_len = path.size() + offsetof(struct sockaddr_un, sun_path) + 1;
  109. } else {
  110. memcpy(addr.sun_path, path.c_str(), path.size());
  111. addr_len = sizeof(sockaddr_un);
  112. }
  113. if (bind(s, reinterpret_cast<sockaddr*>(&addr), addr_len)) {
  114. LOG(ERROR) << "Could not bind unix domain socket to " << path;
  115. if (use_abstract_namespace)
  116. LOG(ERROR) << " (with abstract namespace enabled)";
  117. if (IGNORE_EINTR(close(s)) < 0)
  118. LOG(ERROR) << "close() error";
  119. return kInvalidSocket;
  120. }
  121. return s;
  122. }
  123. void UnixDomainSocket::Accept() {
  124. SocketDescriptor conn = StreamListenSocket::AcceptSocket();
  125. if (conn == kInvalidSocket)
  126. return;
  127. uid_t user_id;
  128. gid_t group_id;
  129. if (!GetPeerIds(conn, &user_id, &group_id) ||
  130. !auth_callback_.Run(user_id, group_id)) {
  131. if (IGNORE_EINTR(close(conn)) < 0)
  132. LOG(ERROR) << "close() error";
  133. return;
  134. }
  135. scoped_ptr<UnixDomainSocket> sock(
  136. new UnixDomainSocket(conn, socket_delegate_, auth_callback_));
  137. // It's up to the delegate to AddRef if it wants to keep it around.
  138. sock->WatchSocket(WAITING_READ);
  139. socket_delegate_->DidAccept(this, sock.PassAs<StreamListenSocket>());
  140. }
  141. UnixDomainSocketFactory::UnixDomainSocketFactory(
  142. const std::string& path,
  143. const UnixDomainSocket::AuthCallback& auth_callback)
  144. : path_(path),
  145. auth_callback_(auth_callback) {}
  146. UnixDomainSocketFactory::~UnixDomainSocketFactory() {}
  147. scoped_ptr<StreamListenSocket> UnixDomainSocketFactory::CreateAndListen(
  148. StreamListenSocket::Delegate* delegate) const {
  149. return UnixDomainSocket::CreateAndListen(
  150. path_, delegate, auth_callback_).PassAs<StreamListenSocket>();
  151. }
  152. #if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
  153. UnixDomainSocketWithAbstractNamespaceFactory::
  154. UnixDomainSocketWithAbstractNamespaceFactory(
  155. const std::string& path,
  156. const std::string& fallback_path,
  157. const UnixDomainSocket::AuthCallback& auth_callback)
  158. : UnixDomainSocketFactory(path, auth_callback),
  159. fallback_path_(fallback_path) {}
  160. UnixDomainSocketWithAbstractNamespaceFactory::
  161. ~UnixDomainSocketWithAbstractNamespaceFactory() {}
  162. scoped_ptr<StreamListenSocket>
  163. UnixDomainSocketWithAbstractNamespaceFactory::CreateAndListen(
  164. StreamListenSocket::Delegate* delegate) const {
  165. return UnixDomainSocket::CreateAndListenWithAbstractNamespace(
  166. path_, fallback_path_, delegate, auth_callback_)
  167. .PassAs<StreamListenSocket>();
  168. }
  169. #endif
  170. } // namespace net