/** * Offer an Unix socket over this stream tube. * * This method offers an Unix socket over this stream tube. The socket address is given as a * a QString, which should contain the path to the socket. Abstract Unix sockets are also supported, * and are given as addresses prefixed with a \c NUL byte. * * If your application uses QLocalServer as the local Unix server implementation, you can use the * offerUnixSocket(const QLocalServer *, const QVariantMap &, bool) overload instead to more easily * pass the server's listen address. * * Note that only connection managers for which supportsUnixSocketsOnLocalhost() or * supportsAbstractUnixSocketsOnLocalhost() is \c true support exporting Unix sockets. * * If supportsUnixSocketsWithCredentials() or supportsAbstractUnixSocketsWithCredentials(), as * appropriate, returns \c true, the \c requireCredentials parameter can be set to \c true to make * the connection manager pass an SCM_CREDS or SCM_CREDENTIALS message as supported by the platform * when making a new connection. This enables preventing other local users from connecting to the * service, but might not be possible to use with all protocols as the message is in-band in the * data stream. * * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver * implemented using TelepathyQt in the other end. * * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready. * * \param socketAddress A valid path to an existing Unix socket or abstract Unix socket. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \param requireCredentials Whether the server requires a SCM_CREDS or SCM_CREDENTIALS message * upon connection. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingOperation *OutgoingStreamTubeChannel::offerUnixSocket( const QString &socketAddress, const QVariantMap ¶meters, bool requireCredentials) { SocketAccessControl accessControl = requireCredentials ? SocketAccessControlCredentials : SocketAccessControlLocalhost; if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) { warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before " "calling offerTube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), OutgoingStreamTubeChannelPtr(this)); } // The tube must be not offered if (state() != TubeChannelStateNotOffered) { warning() << "You can not expose more than a socket for each Stream Tube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), OutgoingStreamTubeChannelPtr(this)); } // In this specific overload, we're handling an Unix/AbstractUnix socket if (socketAddress.startsWith(QLatin1Char('\0'))) { // Abstract Unix socket case // Check if the combination type/access control is supported if ((accessControl == SocketAccessControlLocalhost && !supportsAbstractUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && !supportsAbstractUnixSocketsWithCredentials()) ) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeAbstractUnix); setAccessControl(accessControl); setLocalAddress(socketAddress); PendingVoid *pv = new PendingVoid( interface<Client::ChannelTypeStreamTubeInterface>()->Offer( SocketAddressTypeAbstractUnix, QDBusVariant(QVariant(socketAddress.toLatin1())), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else { // Unix socket case // Check if the combination type/access control is supported if ((accessControl == SocketAccessControlLocalhost && !supportsUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && !supportsUnixSocketsWithCredentials()) || (accessControl != SocketAccessControlLocalhost && accessControl != SocketAccessControlCredentials) ) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeUnix); setAccessControl(accessControl); setLocalAddress(socketAddress); PendingVoid *pv = new PendingVoid( interface<Client::ChannelTypeStreamTubeInterface>()->Offer( SocketAddressTypeUnix, QDBusVariant(QVariant(socketAddress.toLatin1())), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } }
/** * Accept an incoming stream tube as a Unix socket. * * This method accepts an incoming connection request for a stream tube. It can be called * only if the tube is in the #TubeStateLocalPending state. * * An Unix socket (can be used with QLocalSocket or alike) will be opened by the connection manager * as the local tube endpoint. This is only supported if supportsUnixSocketsOnLocalhost() is \c * true. * * You can also specify whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message * upon connection instead of accepting every incoming connection from localhost. This provides * additional security, but requires sending the byte retrieved from * PendingStreamTubeConnection::credentialByte() in-line in the socket byte stream (in a credentials * message if available on the platform), which might not be compatible with all protocols or * libraries. Also, only connection managers for which supportsUnixSocketsWithCredentials() is \c * true support this type of access control. * * This method requires IncomingStreamTubeChannel::FeatureCore to be ready. * * \param requireCredentials Whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message * upon connection. * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). * \sa StreamTubeChannel::supportsUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsUnixSocketsWithCredentials(), * StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() */ PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsUnixSocket( bool requireCredentials) { if (!isReady(IncomingStreamTubeChannel::FeatureCore)) { warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before " "calling acceptTubeAsUnixSocket"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } // The tube must be in local pending state if (state() != TubeChannelStateLocalPending) { warning() << "You can accept tubes only when they are in LocalPending state"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } SocketAccessControl accessControl = requireCredentials ? SocketAccessControlCredentials : SocketAccessControlLocalhost; setAddressType(SocketAddressTypeUnix); setAccessControl(accessControl); // Fail early if the combination is not supported if ((accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeUnix && !supportsUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && addressType() == SocketAddressTypeUnix && !supportsUnixSocketsWithCredentials()) || (accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeAbstractUnix && !supportsAbstractUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && addressType() == SocketAddressTypeAbstractUnix && !supportsAbstractUnixSocketsWithCredentials())) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), IncomingStreamTubeChannelPtr(this)); } QDBusVariant accessControlParam; uchar credentialByte = 0; if (accessControl == SocketAccessControlLocalhost) { accessControlParam.setVariant(qVariantFromValue(static_cast<uint>(0))); } else if (accessControl == SocketAccessControlCredentials) { if (mPriv->initRandom) { qsrand(QTime::currentTime().msec()); mPriv->initRandom = false; } credentialByte = static_cast<uchar>(qrand()); accessControlParam.setVariant(qVariantFromValue(credentialByte)); } else { Q_ASSERT(false); } // Perform the actual call PendingVariant *pv = new PendingVariant( interface<Client::ChannelTypeStreamTubeInterface>()->Accept( addressType(), accessControl, accessControlParam), IncomingStreamTubeChannelPtr(this)); PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(), requireCredentials, credentialByte, IncomingStreamTubeChannelPtr(this)); return op; }
/** * Offer a TCP socket over this stream tube. * * This method offers a TCP socket over this tube. The socket's address is given as * a QHostAddress and a numerical port in native byte order. * * If your application uses QTcpServer as the local TCP server implementation, you can use the * offerTcpSocket(const QTcpServer *, const QVariantMap &) overload instead to more easily pass the * server's listen address. * * It is guaranteed that when the PendingOperation returned by this method will be completed, * the tube will be opened and ready to be used. * * Connection managers adhering to the \telepathy_spec should always support offering IPv4 TCP * sockets. IPv6 sockets are only supported if supportsIPv6SocketsOnLocalhost() is \c true. * * Note that the library will try to use #SocketAccessControlPort access control whenever possible, * as it allows to map connections to users based on their source addresses. If * supportsIPv4SocketsWithSpecifiedAddress() or supportsIPv6SocketsWithSpecifiedAddress() for IPv4 * and IPv6 sockets respectively is \c false, this feature is not available, and the * connectionsForSourceAddresses() map won't contain useful distinct keys. * * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver * implemented using TelepathyQt in the other end. * * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready. * * \param address A valid IPv4 or IPv6 address pointing to an existing socket. * \param port The port the socket is listening for connections to. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingOperation *OutgoingStreamTubeChannel::offerTcpSocket( const QHostAddress &address, quint16 port, const QVariantMap ¶meters) { if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) { warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before " "calling offerTube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), OutgoingStreamTubeChannelPtr(this)); } // The tube must be not offered if (state() != TubeChannelStateNotOffered) { warning() << "You can not expose more than a socket for each Stream Tube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), OutgoingStreamTubeChannelPtr(this)); } SocketAccessControl accessControl = SocketAccessControlLocalhost; // Check if port is supported QHostAddress hostAddress = address; #if QT_VERSION >= 0x050000 if (hostAddress == QHostAddress::Any) { hostAddress = QHostAddress::AnyIPv4; } #endif // In this specific overload, we're handling an IPv4/IPv6 socket if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) { // IPv4 case SocketAccessControl accessControl; // Do some heuristics to find out the best access control.We always prefer port for tracking // connections and source addresses. if (supportsIPv4SocketsWithSpecifiedAddress()) { accessControl = SocketAccessControlPort; } else if (supportsIPv4SocketsOnLocalhost()) { accessControl = SocketAccessControlLocalhost; } else { // There are no combinations supported for this socket warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeIPv4); setAccessControl(accessControl); setIpAddress(qMakePair<QHostAddress, quint16>(hostAddress, port)); SocketAddressIPv4 addr; addr.address = hostAddress.toString(); addr.port = port; PendingVoid *pv = new PendingVoid( interface<Client::ChannelTypeStreamTubeInterface>()->Offer( SocketAddressTypeIPv4, QDBusVariant(QVariant::fromValue(addr)), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) { // IPv6 case // Do some heuristics to find out the best access control.We always prefer port for tracking // connections and source addresses. if (supportsIPv6SocketsWithSpecifiedAddress()) { accessControl = SocketAccessControlPort; } else if (supportsIPv6SocketsOnLocalhost()) { accessControl = SocketAccessControlLocalhost; } else { // There are no combinations supported for this socket warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeIPv6); setAccessControl(accessControl); setIpAddress(qMakePair<QHostAddress, quint16>(hostAddress, port)); SocketAddressIPv6 addr; addr.address = hostAddress.toString(); addr.port = port; PendingVoid *pv = new PendingVoid( interface<Client::ChannelTypeStreamTubeInterface>()->Offer( SocketAddressTypeIPv6, QDBusVariant(QVariant::fromValue(addr)), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else { // We're handling an IPv4/IPv6 socket only warning() << "offerTube can be called only with a QHostAddress representing " "an IPv4 or IPv6 address"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid host given"), OutgoingStreamTubeChannelPtr(this)); } }
/** * Accept an incoming stream tube as a TCP socket. * * This method accepts an incoming connection request for a stream tube. It can be called * only if the tube is in the #TubeStateLocalPending state. * * The connection manager will open a TCP socket for the application to connect to. The address of * the socket will be returned in PendingStreamTubeConnection::ipAddress() once the operation has * finished successfully. * * This overload lets you specify an allowed address/port combination for connecting to the CM * socket. Connections with other source addresses won't be accepted. The accessors * supportsIPv4SocketsWithSpecifiedAddress() and supportsIPv6SocketsWithSpecifiedAddress() can be * used to verify that the connection manager supports this kind of access control; otherwise, this * method will always fail unless QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or * QHostAddress::AnyIPv6 is passed, in which case the behavior is identical to the always supported * acceptTubeAsTcpSocket() overload. * * Note that when using QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or * QHostAddress::AnyIPv6, \a allowedPort is ignored. * * This method requires IncomingStreamTubeChannel::FeatureCore to be ready. * * \param allowedAddress An allowed address for connecting to the socket. * \param allowedPort An allowed port for connecting to the socket. * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsTcpSocket( const QHostAddress &allowedAddress, quint16 allowedPort) { if (!isReady(IncomingStreamTubeChannel::FeatureCore)) { warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before " "calling acceptTubeAsTcpSocket"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } // The tube must be in local pending state if (state() != TubeChannelStateLocalPending) { warning() << "You can accept tubes only when they are in LocalPending state"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } QVariant controlParameter; SocketAccessControl accessControl; QHostAddress hostAddress = allowedAddress; #if QT_VERSION >= 0x050000 if (hostAddress == QHostAddress::Any) { hostAddress = QHostAddress::AnyIPv4; } #endif // Now, let's check what we need to do with accessControl. There is just one special case, Port. if (hostAddress != QHostAddress::Any && #if QT_VERSION >= 0x050000 hostAddress != QHostAddress::AnyIPv4 && #endif hostAddress != QHostAddress::AnyIPv6) { // We need to have a valid QHostAddress AND Port. if (hostAddress.isNull() || allowedPort == 0) { warning() << "You have to set a valid allowed address+port to use Port access control"; return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("The supplied allowed address and/or port was invalid"), IncomingStreamTubeChannelPtr(this)); } accessControl = SocketAccessControlPort; // IPv4 or IPv6? if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) { // IPv4 case SocketAddressIPv4 addr; addr.address = hostAddress.toString(); addr.port = allowedPort; controlParameter = QVariant::fromValue(addr); } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) { // IPv6 case SocketAddressIPv6 addr; addr.address = hostAddress.toString(); addr.port = allowedPort; controlParameter = QVariant::fromValue(addr); } else { // We're handling an IPv4/IPv6 socket only warning() << "acceptTubeAsTcpSocket can be called only with a QHostAddress " "representing an IPv4 or IPv6 address"; return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid host given"), IncomingStreamTubeChannelPtr(this)); } } else { // We have to do no special stuff here accessControl = SocketAccessControlLocalhost; // Since QDBusMarshaller does not like null variants, just add an empty string. controlParameter = QVariant(QString()); } // Set the correct address type and access control setAddressType(hostAddress.protocol() == QAbstractSocket::IPv4Protocol ? SocketAddressTypeIPv4 : SocketAddressTypeIPv6); setAccessControl(accessControl); // Fail early if the combination is not supported if ((accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeIPv4 && !supportsIPv4SocketsOnLocalhost()) || (accessControl == SocketAccessControlPort && addressType() == SocketAddressTypeIPv4 && !supportsIPv4SocketsWithSpecifiedAddress()) || (accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeIPv6 && !supportsIPv6SocketsOnLocalhost()) || (accessControl == SocketAccessControlPort && addressType() == SocketAddressTypeIPv6 && !supportsIPv6SocketsWithSpecifiedAddress())) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), IncomingStreamTubeChannelPtr(this)); } // Perform the actual call PendingVariant *pv = new PendingVariant( interface<Client::ChannelTypeStreamTubeInterface>()->Accept( addressType(), accessControl, QDBusVariant(controlParameter)), IncomingStreamTubeChannelPtr(this)); PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(), false, 0, IncomingStreamTubeChannelPtr(this)); return op; }
void AccessMap::enableAccessControl(int sec) {return setAccessControl(false, false, sec);}
void AccessMap::disableAccessControl(int sec) {return setAccessControl(false, true, sec);}
void AccessMap::disableProcedureOnly(int sec) {return setAccessControl(true, false, sec);}
void AccessMap::enableProcedureOnly(int sec) {return setAccessControl(true, true, sec);}