/src/qtbase/src/dbus/qdbusmisc.cpp
Line | Count | Source |
1 | | // Copyright (C) 2016 The Qt Company Ltd. |
2 | | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include <string.h> |
6 | | |
7 | | #ifndef QT_BOOTSTRAPPED |
8 | | #include <QtCore/qcoreapplication.h> |
9 | | #include <QtCore/qlist.h> |
10 | | #include <QtCore/qmetaobject.h> |
11 | | #include <QtCore/qvariant.h> |
12 | | #include <private/qurl_p.h> |
13 | | |
14 | | #include "qdbusutil_p.h" |
15 | | #include "qdbusconnection_p.h" |
16 | | #include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_* |
17 | | #endif |
18 | | #include "qdbusmetatype_p.h" |
19 | | |
20 | | #ifndef QT_NO_DBUS |
21 | | |
22 | | QT_BEGIN_NAMESPACE |
23 | | |
24 | | using namespace Qt::StringLiterals; |
25 | | |
26 | | bool qDBusCheckAsyncTag(const char *tag) |
27 | 0 | { |
28 | 0 | static const char noReplyTag[] = "Q_NOREPLY"; |
29 | 0 | if (!tag || !*tag) |
30 | 0 | return false; |
31 | | |
32 | 0 | const char *p = strstr(tag, noReplyTag); |
33 | 0 | if (p != nullptr && |
34 | 0 | (p == tag || *(p-1) == ' ') && |
35 | 0 | (p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' ')) |
36 | 0 | return true; |
37 | | |
38 | 0 | return false; |
39 | 0 | } |
40 | | |
41 | | #ifndef QT_BOOTSTRAPPED |
42 | | |
43 | | QString qDBusInterfaceFromMetaObject(const QMetaObject *mo) |
44 | 0 | { |
45 | 0 | QString interface; |
46 | |
|
47 | 0 | int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE); |
48 | 0 | if (idx >= mo->classInfoOffset()) { |
49 | 0 | interface = QLatin1StringView(mo->classInfo(idx).value()); |
50 | 0 | } else { |
51 | 0 | interface = QLatin1StringView(mo->className()); |
52 | 0 | interface.replace("::"_L1, "."_L1); |
53 | |
|
54 | 0 | if (interface.startsWith("QDBus"_L1)) { |
55 | 0 | interface.prepend("org.qtproject.QtDBus."_L1); |
56 | 0 | } else if (interface.startsWith(u'Q') && |
57 | 0 | interface.size() >= 2 && interface.at(1).isUpper()) { |
58 | | // assume it's Qt |
59 | 0 | interface.prepend("org.qtproject.Qt."_L1); |
60 | 0 | } else if (!QCoreApplication::instance()|| |
61 | 0 | QCoreApplication::instance()->applicationName().isEmpty()) { |
62 | 0 | interface.prepend("local."_L1); |
63 | 0 | } else { |
64 | 0 | QString domainName = QCoreApplication::instance()->applicationName(); |
65 | 0 | const QString organizationDomain = QCoreApplication::instance()->organizationDomain(); |
66 | 0 | if (organizationDomain.isEmpty()) |
67 | 0 | domainName.append(".local"_L1); |
68 | 0 | else |
69 | 0 | domainName.append(u'.').append(organizationDomain); |
70 | | |
71 | | // Domain names used to produce interface names should be IDN-encoded. |
72 | 0 | QString encodedDomainName = qt_ACE_do(domainName, ToAceOnly, ForbidLeadingDot); |
73 | 0 | if (encodedDomainName.isEmpty()) { |
74 | 0 | interface.prepend("local."_L1); |
75 | 0 | return interface; |
76 | 0 | } |
77 | | |
78 | | // Hyphens are not allowed in interface names and should be replaced |
79 | | // by underscores. |
80 | 0 | encodedDomainName.replace(u'-', u'_'); |
81 | |
|
82 | 0 | auto nameParts = QStringView{ encodedDomainName }.split(u'.', Qt::SkipEmptyParts); |
83 | |
|
84 | 0 | QString composedDomain; |
85 | | // + 1 for additional dot, e.g. domainName equals "App.example.com", |
86 | | // then composedDomain will be equal "com.example.App." |
87 | 0 | composedDomain.reserve(encodedDomainName.size() + nameParts.size() + 1); |
88 | 0 | for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) { |
89 | | // An interface name cannot start with a digit, and cannot |
90 | | // contain digits immediately following a period. Prefix such |
91 | | // digits with underscores. |
92 | 0 | if (it->first().isDigit()) |
93 | 0 | composedDomain += u'_'; |
94 | 0 | composedDomain += *it + u'.'; |
95 | 0 | } |
96 | |
|
97 | 0 | interface.prepend(composedDomain); |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 0 | return interface; |
102 | 0 | } |
103 | | |
104 | | bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name) |
105 | 0 | { |
106 | 0 | const QMetaObject *mo = obj->metaObject(); |
107 | 0 | for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass()) |
108 | 0 | if (interface_name == qDBusInterfaceFromMetaObject(mo)) |
109 | 0 | return true; |
110 | 0 | return false; |
111 | 0 | } |
112 | | |
113 | | // calculates the metatypes for the method |
114 | | // the slot must have the parameters in the following form: |
115 | | // - zero or more value or const-ref parameters of any kind |
116 | | // - zero or one const ref of QDBusMessage |
117 | | // - zero or more non-const ref parameters |
118 | | // No parameter may be a template. |
119 | | // this function returns -1 if the parameters don't match the above form |
120 | | // this function returns the number of *input* parameters, including the QDBusMessage one if any |
121 | | // this function does not check the return type, so metaTypes[0] is always 0 and always present |
122 | | // metaTypes.count() >= retval + 1 in all cases |
123 | | // |
124 | | // sig must be the normalised signature for the method |
125 | | int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg) |
126 | 0 | { |
127 | 0 | QList<QByteArray> parameterTypes; |
128 | 0 | parameterTypes.reserve(mm.parameterCount()); |
129 | | |
130 | | // Not using QMetaMethod::parameterTypes() since we call QMetaType::fromName below |
131 | | // where we need any typedefs resolved already. |
132 | 0 | for (int i = 0; i < mm.parameterCount(); ++i) { |
133 | 0 | QByteArray typeName = mm.parameterMetaType(i).name(); |
134 | 0 | if (typeName.isEmpty()) |
135 | 0 | typeName = mm.parameterTypeName(i); |
136 | 0 | parameterTypes.append(typeName); |
137 | 0 | } |
138 | |
|
139 | 0 | return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg); |
140 | 0 | } |
141 | | |
142 | | #endif // QT_BOOTSTRAPPED |
143 | | |
144 | | int qDBusParametersForMethod(const QList<QByteArray> ¶meterTypes, QList<QMetaType> &metaTypes, |
145 | | QString &errorMsg) |
146 | 0 | { |
147 | 0 | QDBusMetaTypeId::init(); |
148 | 0 | metaTypes.clear(); |
149 | |
|
150 | 0 | metaTypes.append(QMetaType()); // return type |
151 | 0 | int inputCount = 0; |
152 | 0 | bool seenMessage = false; |
153 | 0 | for (QByteArray type : parameterTypes) { |
154 | 0 | if (type.endsWith('*')) { |
155 | 0 | errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type); |
156 | 0 | return -1; |
157 | 0 | } |
158 | | |
159 | 0 | if (type.endsWith('&')) { |
160 | 0 | QByteArray basictype = type; |
161 | 0 | basictype.truncate(type.size() - 1); |
162 | |
|
163 | 0 | QMetaType id = QMetaType::fromName(basictype); |
164 | 0 | if (!id.isValid()) { |
165 | 0 | errorMsg = "Unregistered output type in parameter list: "_L1 + QLatin1StringView(type); |
166 | 0 | return -1; |
167 | 0 | } else if (QDBusMetaType::typeToSignature(id) == nullptr) |
168 | 0 | return -1; |
169 | | |
170 | 0 | metaTypes.append(id); |
171 | 0 | seenMessage = true; // it cannot appear anymore anyways |
172 | 0 | continue; |
173 | 0 | } |
174 | | |
175 | 0 | if (seenMessage) { // && !type.endsWith('&') |
176 | 0 | errorMsg = "Invalid method, non-output parameters after message or after output parameters: "_L1 + QLatin1StringView(type); |
177 | 0 | return -1; // not allowed |
178 | 0 | } |
179 | | |
180 | 0 | if (type.startsWith("QVector<")) |
181 | 0 | type = "QList<" + type.mid(sizeof("QVector<") - 1); |
182 | |
|
183 | 0 | QMetaType id = QMetaType::fromName(type); |
184 | | #ifdef QT_BOOTSTRAPPED |
185 | | // in bootstrap mode QDBusMessage isn't included, thus we need to resolve it manually here |
186 | | if (type == "QDBusMessage") { |
187 | | id = QDBusMetaTypeId::message(); |
188 | | } |
189 | | #endif |
190 | |
|
191 | 0 | if (!id.isValid()) { |
192 | 0 | errorMsg = "Unregistered input type in parameter list: "_L1 + QLatin1StringView(type); |
193 | 0 | return -1; |
194 | 0 | } |
195 | | |
196 | 0 | if (id == QDBusMetaTypeId::message()) |
197 | 0 | seenMessage = true; |
198 | 0 | else if (QDBusMetaType::typeToSignature(id) == nullptr) { |
199 | 0 | errorMsg = "Type not registered with QtDBus in parameter list: "_L1 + QLatin1StringView(type); |
200 | 0 | return -1; |
201 | 0 | } |
202 | | |
203 | 0 | metaTypes.append(id); |
204 | 0 | ++inputCount; |
205 | 0 | } |
206 | | |
207 | 0 | return inputCount; |
208 | 0 | } |
209 | | |
210 | | QT_END_NAMESPACE |
211 | | |
212 | | #endif // QT_NO_DBUS |