* configure.in: Add test/name-test/Makefile to the generated
[platform/upstream/dbus.git] / dbus / dbus-sysdeps.c
index 917a240..030d080 100644 (file)
@@ -57,7 +57,9 @@
 #ifdef HAVE_BACKTRACE
 #include <execinfo.h>
 #endif
-
+#ifdef HAVE_GETPEERUCRED
+#include <ucred.h>
+#endif
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -396,6 +398,7 @@ _dbus_connect_unix_socket (const char     *path,
                            DBusError      *error)
 {
   int fd;
+  size_t path_len;
   struct sockaddr_un addr;  
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -417,15 +420,23 @@ _dbus_connect_unix_socket (const char     *path,
 
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
+  path_len = strlen (path);
 
   if (abstract)
     {
 #ifdef HAVE_ABSTRACT_SOCKETS
-      /* remember that abstract names aren't nul-terminated so we rely
-       * on sun_path being filled in with zeroes above.
-       */
       addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
-      strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
+      path_len++; /* Account for the extra nul byte added to the start of sun_path */
+
+      if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "Abstract socket name too long\n");
+          close (fd);
+          return -1;
+       }
+       
+      strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
@@ -436,10 +447,18 @@ _dbus_connect_unix_socket (const char     *path,
     }
   else
     {
-      strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
+      if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "Socket name too long\n");
+          close (fd);
+          return -1;
+       }
+
+      strncpy (addr.sun_path, path, path_len);
     }
   
-  if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
+  if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
     {      
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
@@ -487,6 +506,7 @@ _dbus_listen_unix_socket (const char     *path,
 {
   int listen_fd;
   struct sockaddr_un addr;
+  size_t path_len;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -505,6 +525,7 @@ _dbus_listen_unix_socket (const char     *path,
 
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
+  path_len = strlen (path);
   
   if (abstract)
     {
@@ -513,7 +534,17 @@ _dbus_listen_unix_socket (const char     *path,
        * on sun_path being filled in with zeroes above.
        */
       addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
-      strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
+      path_len++; /* Account for the extra nul byte added to the start of sun_path */
+
+      if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "Abstract socket name too long\n");
+          close (listen_fd);
+          return -1;
+       }
+      
+      strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
@@ -542,10 +573,18 @@ _dbus_listen_unix_socket (const char     *path,
           unlink (path);
       }
 
-      strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
+      if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "Abstract socket name too long\n");
+          close (listen_fd);
+          return -1;
+       }
+       
+      strncpy (addr.sun_path, path, path_len);
     }
   
-  if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
+  if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to bind socket \"%s\": %s",
@@ -742,12 +781,40 @@ write_credentials_byte (int             server_fd,
 {
   int bytes_written;
   char buf[1] = { '\0' };
+#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
+  struct {
+         struct cmsghdr hdr;
+         struct cmsgcred cred;
+  } cmsg;
+  struct iovec iov;
+  struct msghdr msg;
+#endif
+
+#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
+  iov.iov_base = buf;
+  iov.iov_len = 1;
+
+  memset (&msg, 0, sizeof (msg));
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  msg.msg_control = &cmsg;
+  msg.msg_controllen = sizeof (cmsg);
+  memset (&cmsg, 0, sizeof (cmsg));
+  cmsg.hdr.cmsg_len = sizeof (cmsg);
+  cmsg.hdr.cmsg_level = SOL_SOCKET;
+  cmsg.hdr.cmsg_type = SCM_CREDS;
+#endif
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   
  again:
 
+#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
+  bytes_written = sendmsg (server_fd, &msg, 0);
+#else
   bytes_written = write (server_fd, buf, 1);
+#endif
 
   if (bytes_written < 0 && errno == EINTR)
     goto again;
@@ -801,8 +868,10 @@ _dbus_read_credentials_unix_socket  (int              client_fd,
   char buf;
 
 #ifdef HAVE_CMSGCRED 
-  char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
-  struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
+  struct {
+         struct cmsghdr hdr;
+         struct cmsgcred cred;
+  } cmsg;
 #endif
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -837,9 +906,9 @@ _dbus_read_credentials_unix_socket  (int              client_fd,
   msg.msg_iovlen = 1;
 
 #ifdef HAVE_CMSGCRED
-  memset (cmsgmem, 0, sizeof (cmsgmem));
-  msg.msg_control = cmsgmem;
-  msg.msg_controllen = sizeof (cmsgmem);
+  memset (&cmsg, 0, sizeof (cmsg));
+  msg.msg_control = &cmsg;
+  msg.msg_controllen = sizeof (cmsg);
 #endif
 
  again:
@@ -862,7 +931,7 @@ _dbus_read_credentials_unix_socket  (int              client_fd,
     }
 
 #ifdef HAVE_CMSGCRED
-  if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
+  if (cmsg.hdr.cmsg_len < sizeof (cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS)
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Message from recvmsg() was not SCM_CREDS");
@@ -890,14 +959,36 @@ _dbus_read_credentials_unix_socket  (int              client_fd,
                       cr_len, (int) sizeof (cr), _dbus_strerror (errno));
       }
 #elif defined(HAVE_CMSGCRED)
-    struct cmsgcred *cred;
-
-    cred = (struct cmsgcred *) CMSG_DATA (cmsg);
-
-    credentials->pid = cred->cmcred_pid;
-    credentials->uid = cred->cmcred_euid;
-    credentials->gid = cred->cmcred_groups[0];
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+    credentials->pid = cmsg.cred.cmcred_pid;
+    credentials->uid = cmsg.cred.cmcred_euid;
+    credentials->gid = cmsg.cred.cmcred_groups[0];
+#elif defined(HAVE_GETPEEREID)
+    uid_t euid;
+    gid_t egid;
+    if (getpeereid (client_fd, &euid, &egid) == 0)
+      {
+        credentials->uid = euid;
+        credentials->gid = egid;
+      }
+    else
+      {
+        _dbus_verbose ("Failed to getpeereid() credentials: %s\n", _dbus_strerror (errno));
+      }
+#elif defined(HAVE_GETPEERUCRED)
+    ucred_t * ucred = NULL;
+    if (getpeerucred (client_fd, &ucred) == 0)
+      {
+        credentials->pid = ucred_getpid (ucred);
+        credentials->uid = ucred_geteuid (ucred);
+        credentials->gid = ucred_getegid (ucred);
+      }
+    else
+      {
+        _dbus_verbose ("Failed to getpeerucred() credentials: %s\n", _dbus_strerror (errno));
+      }
+    if (ucred != NULL)
+      ucred_free (ucred);
+#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEEREID && !HAVE_GETPEERUCRED */
     _dbus_verbose ("Socket credentials not supported on this OS\n");
 #endif
   }
@@ -1135,6 +1226,7 @@ _dbus_string_parse_int (const DBusString *str,
 * Checks to make sure the given directory is 
 * private to the user 
 *
+* @param dir the name of the directory
 * @param error error return
 * @returns #FALSE on failure
 **/
@@ -1167,8 +1259,6 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* Not currently used, so only built when tests are enabled */
 /**
  * Parses an unsigned integer contained in a DBusString. Either return
  * parameter may be #NULL if you aren't interested in it. The integer
@@ -1207,7 +1297,6 @@ _dbus_string_parse_uint (const DBusString *str,
 
   return TRUE;
 }
-#endif /* DBUS_BUILD_TESTS */
 
 #ifdef DBUS_BUILD_TESTS
 static dbus_bool_t