Beispiel #1
0
static errno_t
sbus_server_bus_get_connection_unix_process_id(TALLOC_CTX *mem_ctx,
                                               struct sbus_request *sbus_req,
                                               struct sbus_server *server,
                                               const char *name,
                                               uint32_t *_pid)
{
    struct sbus_connection *conn;
    unsigned long pid;
    dbus_bool_t dbret;

    if (strcmp(name, DBUS_SERVICE_DBUS) == 0) {
        *_pid = getpid();
        return EOK;
    }

    conn = sss_ptr_hash_lookup(server->names, name, struct sbus_connection);
    if (conn == NULL) {
        return ERR_SBUS_UNKNOWN_OWNER;
    }

    dbret = dbus_connection_get_unix_process_id(conn->connection, &pid);
    if (!dbret) {
        return EIO;
    }

    *_pid = (uint32_t)pid;
    return EOK;
}
static dbus_bool_t
bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
						  BusTransaction *transaction,
						  DBusMessage    *message,
						  DBusError      *error)
{
  const char *service;
  DBusString str;
  BusRegistry *registry;
  BusService *serv;
  DBusConnection *conn;
  DBusMessage *reply;
  unsigned long pid;
  dbus_uint32_t pid32;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  registry = bus_connection_get_registry (connection);

  service = NULL;
  reply = NULL;

  if (! dbus_message_get_args (message, error,
			       DBUS_TYPE_STRING, &service,
			       DBUS_TYPE_INVALID))
      goto failed;

  _dbus_verbose ("asked for PID of connection %s\n", service);

  _dbus_string_init_const (&str, service);
  serv = bus_registry_lookup (registry, &str);
  if (serv == NULL)
    {
      dbus_set_error (error, 
		      DBUS_ERROR_NAME_HAS_NO_OWNER,
		      "Could not get PID of name '%s': no such name", service);
      goto failed;
    }

  conn = bus_service_get_primary_owners_connection (serv);

  reply = dbus_message_new_method_return (message);
  if (reply == NULL)
    goto oom;

  if (!dbus_connection_get_unix_process_id (conn, &pid))
    {
      dbus_set_error (error,
                      DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
                      "Could not determine PID for '%s'", service);
      goto failed;
    }

  pid32 = pid;
  if (! dbus_message_append_args (reply,
                                  DBUS_TYPE_UINT32, &pid32,
                                  DBUS_TYPE_INVALID))
    goto oom;

  if (! bus_transaction_send_from_driver (transaction, connection, reply))
    goto oom;

  dbus_message_unref (reply);

  return TRUE;

 oom:
  BUS_SET_OOM (error);

 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  if (reply)
    dbus_message_unref (reply);
  return FALSE;
}
Beispiel #3
0
/**
 * session_from_dbus:
 * @parent: parent,
 * @message: D-Bus message.
 *
 * Create a new session, based on the specified D-Bus message.
 *
 * Return new Session, or NULL on error.
 **/
Session *
session_from_dbus (const void     *parent,
		   NihDBusMessage *message)
{
	const char     *sender;
	DBusError       dbus_error;
	unsigned long   unix_user;
	unsigned long   unix_process_id;
	char            root[PATH_MAX];
	Session        *session;
	struct passwd  *pwd;
	nih_local char *conf_path = NULL;

	nih_assert (message != NULL);

	/* Handle explicit command-line request and alternative request
	 * method (primarily for test framework) to disable session support.
	 */
	if (disable_sessions || getenv ("UPSTART_NO_SESSIONS"))
		return NULL;

	session_init ();

	/* Ask D-Bus nicely for the origin uid and/or pid of the caller;
	 * sadly we can't ask the bus daemon for the origin pid, so that
	 * one will just have to stay user-session only.
	 */
	dbus_error_init (&dbus_error);

	sender = dbus_message_get_sender (message->message);
	if (sender) {
		unix_user = dbus_bus_get_unix_user (message->connection, sender,
						    &dbus_error);
		if (unix_user == (unsigned long)-1) {
			dbus_error_free (&dbus_error);
			unix_user = 0;
		}

		unix_process_id = 0;

	} else {
		if (! dbus_connection_get_unix_user (message->connection,
						     &unix_user))
			unix_process_id = 0;

		if (! dbus_connection_get_unix_process_id (message->connection,
							   &unix_process_id))
			unix_process_id = 0;
	}

	/* If we retrieved a process id, look up the root path for it;
	 * if it's just '/' don't worry so much about it.
	 */
	if (unix_process_id) {
		nih_local char *symlink = NULL;
		ssize_t len;

		symlink = NIH_MUST (nih_sprintf (NULL, "/proc/%lu/root",
						 unix_process_id));
		len = readlink (symlink, root, sizeof root);
		if (len < 0)
			return NULL;

		root[len] = '\0';

		if (! strcmp (root, "/")) {
			unix_process_id = 0;
			if (! unix_user)
				return NULL;
		}

	} else if (! unix_user) {
		/* No process id or user id found, return the NULL session */
		return NULL;
	}

	if (unix_user) {
		pwd = getpwuid (unix_user);

		if (! pwd || ! pwd->pw_dir) {
			nih_error ("%lu: %s: %s", unix_user,
				   _("Unable to lookup home directory"),
				   strerror (errno));
			return NULL;
		}

		NIH_MUST (nih_strcat_sprintf (&conf_path, NULL, "%s/%s",
					pwd->pw_dir, USERCONFDIR));
	}


	/* Now find in the existing Sessions list */
	NIH_LIST_FOREACH_SAFE (sessions, iter) {
		Session *session = (Session *)iter;

		if (unix_process_id) {
			if (! session->chroot)
				continue;

			/* ignore sessions relating to other chroots */
			if (strcmp (session->chroot, root))
				continue;
		}

		/* ignore sessions relating to other users */
		if (unix_user != session->user)
			continue;

		/* Found a user with the same uid but different
		 * conf_dir to the existing session user. Either the
		 * original user has been deleted and a new user created
		 * with the same uid, or the original users home
		 * directory has changed since they first started
		 * running jobs. Whatever the reason, we (can only) honour
		 * the new value.
		 *
		 * Since multiple users with the same uid are considered
		 * to be "the same user", invalidate the old path,
		 * allowing the correct new path to be set below.
		 *
		 * Note that there may be a possibility of trouble if
		 * the scenario relates to a deleted user and that original
		 * user still has jobs running. However, if that were the
		 * case, those jobs would likely fail anyway since they
		 * would have no working directory due to the original
		 * users home directory being deleted/changed/made inaccessible.
		 */
		if (unix_user && conf_path && session->conf_path &&
				strcmp (conf_path, session->conf_path)) {
			nih_free (session->conf_path);
			session->conf_path = NULL;
		}

		if (! session->conf_path)
			session_create_conf_source (session);

		return session;
	}
Beispiel #4
0
/**
 * Check if Apparmor security controls allow the message to be sent to a
 * particular connection based on the security context of the sender and
 * that of the receiver. The destination connection need not be the
 * addressed recipient, it could be an "eavesdropper"
 *
 * @param sender the sender of the message.
 * @param proposed_recipient the connection the message is to be sent to.
 * @param requested_reply TRUE if the message is a reply requested by
 *                        proposed_recipient
 * @param bustype name of the bus
 * @param msgtype message type (DBUS_MESSAGE_TYPE_METHOD_CALL, etc.)
 * @param path object path the message should be sent to
 * @param interface the type of the object instance
 * @param member the member of the object
 * @param error_name the name of the error if the message type is error
 * @param destination name that the message should be sent to
 * @param source name that the message should be sent from
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if the message is permitted
 */
dbus_bool_t
bus_apparmor_allows_send (DBusConnection     *sender,
                          DBusConnection     *proposed_recipient,
                          dbus_bool_t         requested_reply,
                          const char         *bustype,
                          int                 msgtype,
                          const char         *path,
                          const char         *interface,
                          const char         *member,
                          const char         *error_name,
                          const char         *destination,
                          const char         *source,
                          BusActivationEntry *activation_entry,
                          DBusError          *error)
{
#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *src_con = NULL, *dst_con = NULL;
  DBusString qstr, auxdata;
  int src_allow = FALSE, dst_allow = FALSE;
  int src_audit = TRUE, dst_audit = TRUE;
  dbus_bool_t free_auxdata = FALSE;
  unsigned long pid;
  int len, res, src_errno = 0, dst_errno = 0;
  uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE;
  const char *msgtypestr = dbus_message_type_to_string(msgtype);
  const char *dst_label = NULL;
  const char *dst_mode = NULL;

  if (!apparmor_enabled)
    return TRUE;

  _dbus_assert (sender != NULL);

  src_con = bus_connection_dup_apparmor_confinement (sender);

  if (proposed_recipient)
    {
      dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient);
    }
  else if (activation_entry != NULL)
    {
      dst_label = bus_activation_entry_get_assumed_apparmor_label (activation_entry);
    }
  else
    {
      dst_con = bus_con;
      bus_apparmor_confinement_ref (dst_con);
    }

  if (dst_con != NULL)
    {
      dst_label = dst_con->label;
      dst_mode = dst_con->mode;
    }

  /* map reply messages to initial send and receive permission. That is
   * permission to receive a message from X grants permission to reply to X.
   * And permission to send a message to Y grants permission to receive a reply
   * from Y. Note that this only applies to requested replies. Unrequested
   * replies still require a policy query.
   */
  if (requested_reply)
    {
      /* ignore requested reply messages and let dbus reply mapping handle them
       * as the send was already allowed
       */
      src_allow = TRUE;
      dst_allow = TRUE;
      goto out;
    }

  if (is_unconfined (src_con->label, src_con->mode))
    {
      src_allow = TRUE;
      src_audit = FALSE;
    }
  else
    {
      if (!_dbus_string_init (&qstr))
        goto oom;

      if (!build_message_query (&qstr, src_con->label, bustype, destination,
                                dst_label, path, interface, member))
        {
          _dbus_string_free (&qstr);
          goto oom;
        }

      res = aa_query_label (src_perm,
                            _dbus_string_get_data (&qstr),
                            _dbus_string_get_length (&qstr),
                            &src_allow, &src_audit);
      _dbus_string_free (&qstr);
      if (res == -1)
        {
          src_errno = errno;
          set_error_from_query_errno (error, src_errno);
          goto audit;
        }
    }

  /* When deciding whether we can activate a service, we only check that
   * we are allowed to send a message to it, not that it is allowed to
   * receive that message from us.
   */
  if (activation_entry != NULL || is_unconfined (dst_label, dst_mode))
    {
      dst_allow = TRUE;
      dst_audit = FALSE;
    }
  else
    {
      if (!_dbus_string_init (&qstr))
        goto oom;

      if (!build_message_query (&qstr, dst_label, bustype, source,
                                src_con->label, path, interface, member))
        {
          _dbus_string_free (&qstr);
          goto oom;
        }

      res = aa_query_label (dst_perm,
                            _dbus_string_get_data (&qstr),
                            _dbus_string_get_length (&qstr),
                            &dst_allow, &dst_audit);
      _dbus_string_free (&qstr);
      if (res == -1)
        {
          dst_errno = errno;
          set_error_from_query_errno (error, dst_errno);
          goto audit;
        }
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (src_con->mode))
    src_allow = TRUE;
  if (modestr_is_complain (dst_mode))
    dst_allow = TRUE;

  if (!src_allow || !dst_allow)
    set_error_from_denied_message (error,
                                   sender,
                                   proposed_recipient,
                                   requested_reply,
                                   msgtypestr,
                                   path,
                                   interface,
                                   member,
                                   error_name,
                                   destination);

  /* Don't audit the message if one of the following conditions is true:
   *   1) The AppArmor query indicates that auditing should not happen.
   *   2) The message is a reply type. Reply message are not audited because
   *      the AppArmor policy language does not have the notion of a reply
   *      message. Unrequested replies will be silently discarded if the sender
   *      does not have permission to send to the receiver or if the receiver
   *      does not have permission to receive from the sender.
   */
  if ((!src_audit && !dst_audit) ||
      (msgtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
       msgtype == DBUS_MESSAGE_TYPE_ERROR))
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (path && !_dbus_append_pair_str (&auxdata, "path", path))
    goto oom;

  if (interface && !_dbus_append_pair_str (&auxdata, "interface", interface))
    goto oom;

  if (member && !_dbus_append_pair_str (&auxdata, "member", member))
    goto oom;

  if (error_name && !_dbus_append_pair_str (&auxdata, "error_name", error_name))
    goto oom;

  len = _dbus_string_get_length (&auxdata);

  if (src_audit)
    {
      if (!_dbus_append_mask (&auxdata, src_perm))
        goto oom;

      if (destination && !_dbus_append_pair_str (&auxdata, "name", destination))
        goto oom;

      if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "pid", pid))
        goto oom;

      if (src_con->label &&
          !_dbus_append_pair_str (&auxdata, "label", src_con->label))
        goto oom;

      if (proposed_recipient &&
          dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
        goto oom;

      if (dst_label &&
          !_dbus_append_pair_str (&auxdata, "peer_label", dst_label))
        goto oom;

      if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno)))
        goto oom;

      if (dst_errno &&
          !_dbus_append_pair_str (&auxdata, "peer_info", strerror (dst_errno)))
        goto oom;

      log_message (src_allow, msgtypestr, &auxdata);
    }
  if (dst_audit)
    {
      _dbus_string_set_length (&auxdata, len);

      if (source && !_dbus_append_pair_str (&auxdata, "name", source))
        goto oom;

      if (!_dbus_append_mask (&auxdata, dst_perm))
        goto oom;

      if (proposed_recipient &&
          dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "pid", pid))
        goto oom;

      if (dst_label &&
          !_dbus_append_pair_str (&auxdata, "label", dst_label))
        goto oom;

      if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
        goto oom;

      if (src_con->label &&
          !_dbus_append_pair_str (&auxdata, "peer_label", src_con->label))
        goto oom;

      if (dst_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (dst_errno)))
        goto oom;

      if (src_errno &&
          !_dbus_append_pair_str (&auxdata, "peer_info", strerror (src_errno)))
        goto oom;

      log_message (dst_allow, msgtypestr, &auxdata);
    }

 out:
  if (src_con != NULL)
    bus_apparmor_confinement_unref (src_con);
  if (dst_con != NULL)
    bus_apparmor_confinement_unref (dst_con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);

  return src_allow && dst_allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  src_allow = FALSE;
  dst_allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
Beispiel #5
0
/**
 * Returns true if the given connection can acquire a service,
 * using the tasks security context
 *
 * @param connection connection that wants to own the service
 * @param bustype name of the bus
 * @param service_name the name of the service to acquire
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if acquire is permitted
 */
dbus_bool_t
bus_apparmor_allows_acquire_service (DBusConnection     *connection,
                                     const char         *bustype,
                                     const char         *service_name,
                                     DBusError          *error)
{

#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *con = NULL;
  DBusString qstr, auxdata;
  dbus_bool_t free_auxdata = FALSE;
  /* the AppArmor API uses pointers to int for pointers to boolean, and
   * int is not strictly guaranteed to be the same as dbus_bool_t */
  int allow = FALSE, audit = TRUE;
  unsigned long pid;
  int res, serrno = 0;

  if (!apparmor_enabled)
    return TRUE;

  _dbus_assert (connection != NULL);

  con = bus_connection_dup_apparmor_confinement (connection);

  if (is_unconfined (con->label, con->mode))
    {
      allow = TRUE;
      audit = FALSE;
      goto out;
    }

  if (!_dbus_string_init (&qstr))
    goto oom;

  if (!build_service_query (&qstr, con->label, bustype, service_name))
    {
      _dbus_string_free (&qstr);
      goto oom;
    }

  res = aa_query_label (AA_DBUS_BIND,
                        _dbus_string_get_data (&qstr),
                        _dbus_string_get_length (&qstr),
                        &allow, &audit);
  _dbus_string_free (&qstr);
  if (res == -1)
    {
      serrno = errno;
      set_error_from_query_errno (error, serrno);
      goto audit;
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (con->mode))
      allow = TRUE;

  if (!allow)
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                    "Connection \"%s\" is not allowed to own the service "
                    "\"%s\" due to AppArmor policy",
                    bus_connection_is_active (connection) ?
                     bus_connection_get_name (connection) : "(inactive)",
                    service_name);

  if (!audit)
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (!_dbus_append_pair_str (&auxdata, "name", service_name))
    goto oom;

  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
    goto oom;

  if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
    goto oom;

  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
      !_dbus_append_pair_uint (&auxdata, "pid", pid))
    goto oom;

  if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
    goto oom;

  log_message (allow, "bind", &auxdata);

 out:
  if (con != NULL)
    bus_apparmor_confinement_unref (con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);
  return allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
Beispiel #6
0
/**
 * Check if Apparmor security controls allow the connection to eavesdrop on
 * other connections.
 *
 * @param connection the connection attempting to eavesdrop.
 * @param bustype name of the bus
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if eavesdropping is permitted
 */
dbus_bool_t
bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
                                   const char         *bustype,
                                   DBusError          *error)
{
#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *con = NULL;
  DBusString qstr, auxdata;
  int allow = FALSE, audit = TRUE;
  dbus_bool_t free_auxdata = FALSE;
  unsigned long pid;
  int res, serrno = 0;

  if (!apparmor_enabled)
    return TRUE;

  con = bus_connection_dup_apparmor_confinement (connection);

  if (is_unconfined (con->label, con->mode))
    {
      allow = TRUE;
      audit = FALSE;
      goto out;
    }

  if (!_dbus_string_init (&qstr))
    goto oom;

  if (!build_eavesdrop_query (&qstr, con->label, bustype))
    {
      _dbus_string_free (&qstr);
      goto oom;
    }

  res = aa_query_label (AA_DBUS_EAVESDROP,
                        _dbus_string_get_data (&qstr),
                        _dbus_string_get_length (&qstr),
                        &allow, &audit);
  _dbus_string_free (&qstr);
  if (res == -1)
    {
      serrno = errno;
      set_error_from_query_errno (error, serrno);
      goto audit;
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (con->mode))
    allow = TRUE;

  if (!allow)
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                    "Connection \"%s\" is not allowed to eavesdrop due to "
                    "AppArmor policy",
                    bus_connection_is_active (connection) ?
                    bus_connection_get_name (connection) : "(inactive)");

  if (!audit)
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
    goto oom;

  if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
    goto oom;

  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
      !_dbus_append_pair_uint (&auxdata, "pid", pid))
    goto oom;

  if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
    goto oom;

  log_message (allow, "eavesdrop", &auxdata);

 out:
  if (con != NULL)
    bus_apparmor_confinement_unref (con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);

  return allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}