Logo Search packages:      
Sourcecode: dbus version File versions

dbus_bool_t _dbus_read_credentials_unix_socket ( int  client_fd,
DBusCredentials credentials,
DBusError error 
)

Reads a single byte which must be nul (an error occurs otherwise), and reads unix credentials if available. Fills in pid/uid/gid with -1 if no credentials are available. Return value indicates whether a byte was read, not whether we got valid credentials. On some systems, such as Linux, reading/writing the byte isn't actually required, but we do it anyway just to avoid multiple codepaths.

Fails if no byte is available, so you must select() first.

The point of the byte is that on some systems we have to use sendmsg()/recvmsg() to transmit credentials.

Parameters:
client_fd the client file descriptor
credentials struct to fill with credentials of client
error location to store error code
Returns:
TRUE on success

Definition at line 793 of file dbus-sysdeps.c.

References _dbus_assert, _dbus_credentials_clear(), _dbus_error_from_errno(), _dbus_strerror(), dbus_set_error(), FALSE, DBusCredentials::gid, DBusCredentials::pid, TRUE, and DBusCredentials::uid.

{
  struct msghdr msg;
  struct iovec iov;
  char buf;

#ifdef HAVE_CMSGCRED 
  char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
  struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
#endif

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  /* The POSIX spec certainly doesn't promise this, but
   * we need these assertions to fail as soon as we're wrong about
   * it so we can do the porting fixups
   */
  _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid));
  _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid));
  _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid));

  _dbus_credentials_clear (credentials);

#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
  /* Set the socket to receive credentials on the next message */
  {
    int on = 1;
    if (setsockopt (client_fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
      {
      _dbus_verbose ("Unable to set LOCAL_CREDS socket option\n");
      return FALSE;
      }
  }
#endif

  iov.iov_base = &buf;
  iov.iov_len = 1;

  memset (&msg, 0, sizeof (msg));
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

#ifdef HAVE_CMSGCRED
  memset (cmsgmem, 0, sizeof (cmsgmem));
  msg.msg_control = cmsgmem;
  msg.msg_controllen = sizeof (cmsgmem);
#endif

 again:
  if (recvmsg (client_fd, &msg, 0) < 0)
    {
      if (errno == EINTR)
      goto again;

      dbus_set_error (error, _dbus_error_from_errno (errno),
                      "Failed to read credentials byte: %s",
                      _dbus_strerror (errno));
      return FALSE;
    }

  if (buf != '\0')
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Credentials byte was not nul");
      return FALSE;
    }

#ifdef HAVE_CMSGCRED
  if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED);
      _dbus_verbose ("Message from recvmsg() was not SCM_CREDS\n");
      return FALSE;
    }
#endif

  _dbus_verbose ("read credentials byte\n");

  {
#ifdef SO_PEERCRED
    struct ucred cr;   
    int cr_len = sizeof (cr);
   
    if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
      cr_len == sizeof (cr))
      {
      credentials->pid = cr.pid;
      credentials->uid = cr.uid;
      credentials->gid = cr.gid;
      }
    else
      {
      _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
                   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 */
    _dbus_verbose ("Socket credentials not supported on this OS\n");
#endif
  }

  _dbus_verbose ("Credentials:"
                 "  pid "DBUS_PID_FORMAT
                 "  uid "DBUS_UID_FORMAT
                 "  gid "DBUS_GID_FORMAT"\n",
             credentials->pid,
             credentials->uid,
             credentials->gid);
    
  return TRUE;
}


Generated by  Doxygen 1.6.0   Back to index