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.

client_fd the client file descriptor
credentials struct to fill with credentials of client
error location to store error code
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;

  char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
  struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;

  /* 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;

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

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

  memset (cmsgmem, 0, sizeof (cmsgmem));
  msg.msg_control = cmsgmem;
  msg.msg_controllen = sizeof (cmsgmem);

  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;

  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;

  _dbus_verbose ("read credentials byte\n");

    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;
      _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];
    _dbus_verbose ("Socket credentials not supported on this OS\n");

  _dbus_verbose ("Credentials:"
                 "  pid "DBUS_PID_FORMAT
                 "  uid "DBUS_UID_FORMAT
                 "  gid "DBUS_GID_FORMAT"\n",
  return TRUE;

Generated by  Doxygen 1.6.0   Back to index