1 | /* $Id: wayland-helper-ipc.cpp 102064 2023-11-10 14:15:11Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * Guest Additions - IPC between VBoxClient and vboxwl tool.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 | #include <sys/types.h>
|
---|
29 | #include <pwd.h>
|
---|
30 | #include <unistd.h>
|
---|
31 |
|
---|
32 | #include <iprt/cdefs.h>
|
---|
33 | #include <iprt/err.h>
|
---|
34 | #include <iprt/linux/sysfs.h>
|
---|
35 | #include <iprt/localipc.h>
|
---|
36 | #include <iprt/mem.h>
|
---|
37 | #include <iprt/crc.h>
|
---|
38 | #include <iprt/env.h>
|
---|
39 | #include <iprt/process.h>
|
---|
40 | #include <iprt/asm.h>
|
---|
41 |
|
---|
42 | #include <VBox/GuestHost/clipboard-helper.h>
|
---|
43 |
|
---|
44 | #include "VBoxClient.h"
|
---|
45 | #include "wayland-helper-ipc.h"
|
---|
46 |
|
---|
47 | RTDECL(int) vbcl_wayland_hlp_gtk_ipc_srv_name(char *szBuf, size_t cbBuf)
|
---|
48 | {
|
---|
49 | int rc;
|
---|
50 |
|
---|
51 | char pszActiveTTY[128];
|
---|
52 | size_t cchRead;
|
---|
53 | struct passwd *pwd;
|
---|
54 |
|
---|
55 | AssertReturn(RT_VALID_PTR(szBuf), VERR_INVALID_PARAMETER);
|
---|
56 | AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
|
---|
57 |
|
---|
58 | RT_BZERO(szBuf, cbBuf);
|
---|
59 | RT_ZERO(pszActiveTTY);
|
---|
60 |
|
---|
61 | rc = RTStrCat(szBuf, cbBuf, "GtkHlpIpcServer-");
|
---|
62 | if (RT_SUCCESS(rc))
|
---|
63 | rc = RTLinuxSysFsReadStrFile(pszActiveTTY, sizeof(pszActiveTTY) - 1 /* reserve last byte for string termination */,
|
---|
64 | &cchRead, "class/tty/tty0/active");
|
---|
65 | if (RT_SUCCESS(rc))
|
---|
66 | rc = RTStrCat(szBuf, cbBuf, pszActiveTTY);
|
---|
67 |
|
---|
68 | if (RT_SUCCESS(rc))
|
---|
69 | rc = RTStrCat(szBuf, cbBuf, "-");
|
---|
70 |
|
---|
71 | pwd = getpwuid(geteuid());
|
---|
72 | if (RT_VALID_PTR(pwd))
|
---|
73 | {
|
---|
74 | if (RT_VALID_PTR(pwd->pw_name))
|
---|
75 | rc = RTStrCat(szBuf, cbBuf, pwd->pw_name);
|
---|
76 | else
|
---|
77 | rc = VERR_NOT_FOUND;
|
---|
78 | }
|
---|
79 | else
|
---|
80 | rc = VERR_NOT_FOUND;
|
---|
81 |
|
---|
82 | return rc;
|
---|
83 | }
|
---|
84 |
|
---|
85 | void vbcl::ipc::packet_dump(vbcl::ipc::packet_t *pPacket)
|
---|
86 | {
|
---|
87 | VBClLogVerbose(3, "IPC packet dump:\n");
|
---|
88 | VBClLogVerbose(3, "u64Crc : 0x%x\n", pPacket->u64Crc);
|
---|
89 | VBClLogVerbose(3, "uSessionId: %u\n", pPacket->uSessionId);
|
---|
90 | VBClLogVerbose(3, "idCmd : %u\n", pPacket->idCmd);
|
---|
91 | VBClLogVerbose(3, "cbData: : %u\n", pPacket->cbData);
|
---|
92 | }
|
---|
93 |
|
---|
94 | bool vbcl::ipc::packet_verify(vbcl::ipc::packet_t *pPacket, size_t cbPacket)
|
---|
95 | {
|
---|
96 | bool fResult = false;
|
---|
97 |
|
---|
98 | AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
|
---|
99 | AssertReturn(cbPacket > sizeof(vbcl::ipc::packet_t), VERR_INVALID_PARAMETER);
|
---|
100 |
|
---|
101 | AssertReturn( pPacket->idCmd > vbcl::ipc::CMD_UNKNOWN
|
---|
102 | && pPacket->idCmd < vbcl::ipc::CMD_MAX, VERR_INVALID_PARAMETER);
|
---|
103 |
|
---|
104 | /* Exact size match. */
|
---|
105 | if (pPacket->cbData == cbPacket)
|
---|
106 | {
|
---|
107 | /* CRC check. */
|
---|
108 | uint64_t u64Crc = pPacket->u64Crc;
|
---|
109 | pPacket->u64Crc = 0;
|
---|
110 | if (u64Crc != 0 && RTCrc64(pPacket, pPacket->cbData) == u64Crc)
|
---|
111 | {
|
---|
112 | /* Verify payload size. */
|
---|
113 | size_t cbPayload = 0;
|
---|
114 |
|
---|
115 | switch (pPacket->idCmd)
|
---|
116 | {
|
---|
117 | case vbcl::ipc::CLIP_FORMATS:
|
---|
118 | case vbcl::ipc::CLIP_FORMAT:
|
---|
119 | cbPayload = sizeof(vbcl::ipc::clipboard::formats_packet_t);
|
---|
120 | break;
|
---|
121 |
|
---|
122 | case vbcl::ipc::CLIP_DATA:
|
---|
123 | {
|
---|
124 | vbcl::ipc::clipboard::data_packet_t *pDataEx = (vbcl::ipc::clipboard::data_packet_t *)pPacket;
|
---|
125 | cbPayload = sizeof(vbcl::ipc::clipboard::data_packet_t) + pDataEx->cbData;
|
---|
126 | break;
|
---|
127 | }
|
---|
128 |
|
---|
129 | default:
|
---|
130 | break;
|
---|
131 | }
|
---|
132 |
|
---|
133 | if (pPacket->cbData == cbPayload)
|
---|
134 | fResult = true;
|
---|
135 | else
|
---|
136 | VBClLogVerbose(3, "bad cmd size (%u vs %u)\n", pPacket->cbData, cbPayload);
|
---|
137 | }
|
---|
138 | else
|
---|
139 | VBClLogVerbose(3, "bad crc\n");
|
---|
140 |
|
---|
141 | /* Restore CRC. */
|
---|
142 | pPacket->u64Crc = u64Crc;
|
---|
143 | }
|
---|
144 | else
|
---|
145 | VBClLogVerbose(3, "bad size\n");
|
---|
146 |
|
---|
147 | return fResult;
|
---|
148 | }
|
---|
149 |
|
---|
150 | int vbcl::ipc::packet_read(uint32_t uSessionId, RTLOCALIPCSESSION hSession, void **ppvData)
|
---|
151 | {
|
---|
152 | int rc;
|
---|
153 |
|
---|
154 | vbcl::ipc::packet_t Packet;
|
---|
155 |
|
---|
156 | AssertPtrReturn(ppvData, VERR_INVALID_PARAMETER);
|
---|
157 |
|
---|
158 | rc = RTLocalIpcSessionWaitForData(hSession, VBOX_GTKIPC_RX_TIMEOUT_MS);
|
---|
159 | if (RT_SUCCESS(rc))
|
---|
160 | {
|
---|
161 | /* Read IPC message header. */
|
---|
162 | rc = RTLocalIpcSessionRead(hSession, &Packet, sizeof(Packet), NULL);
|
---|
163 | if (RT_SUCCESS(rc))
|
---|
164 | {
|
---|
165 | bool fCheck = true;
|
---|
166 |
|
---|
167 | #define _CHECK(_cond, _msg, _ptr) \
|
---|
168 | if (fCheck) \
|
---|
169 | { \
|
---|
170 | fCheck &= _cond; \
|
---|
171 | if (!fCheck) \
|
---|
172 | VBClLogVerbose(3, _msg "\n", _ptr); \
|
---|
173 | }
|
---|
174 |
|
---|
175 | _CHECK(Packet.u64Crc > 0, "bad crc: 0x%x", Packet.u64Crc);
|
---|
176 | _CHECK(Packet.uSessionId == uSessionId, "bad session id: %u vs %u", (Packet.uSessionId, uSessionId));
|
---|
177 | _CHECK(Packet.cbData > sizeof(Packet), "bad cbData: %u", Packet.cbData);
|
---|
178 |
|
---|
179 | /* Receive the rest of a message. */
|
---|
180 | if (fCheck)
|
---|
181 | {
|
---|
182 | uint8_t *puData;
|
---|
183 |
|
---|
184 | puData = (uint8_t *)RTMemAllocZ(Packet.cbData);
|
---|
185 | if (RT_VALID_PTR(puData))
|
---|
186 | {
|
---|
187 | /* Add generic header to the beginning of the output buffer
|
---|
188 | * and receive the rest of the data into it. */
|
---|
189 | memcpy(puData, &Packet, sizeof(Packet));
|
---|
190 |
|
---|
191 | rc = RTLocalIpcSessionRead(hSession, puData + sizeof(Packet),
|
---|
192 | Packet.cbData - sizeof(Packet), NULL);
|
---|
193 | if (RT_SUCCESS(rc))
|
---|
194 | {
|
---|
195 | if (vbcl::ipc::packet_verify((vbcl::ipc::packet_t *)puData, Packet.cbData))
|
---|
196 | {
|
---|
197 | /* Now return received data to the caller. */
|
---|
198 | *ppvData = puData;
|
---|
199 | }
|
---|
200 | else
|
---|
201 | rc = VERR_NOT_EQUAL;
|
---|
202 | }
|
---|
203 |
|
---|
204 | if (RT_FAILURE(rc))
|
---|
205 | RTMemFree(puData);
|
---|
206 | }
|
---|
207 | else
|
---|
208 | rc = VERR_NO_MEMORY;
|
---|
209 | }
|
---|
210 | else
|
---|
211 | rc = VERR_INVALID_PARAMETER;
|
---|
212 |
|
---|
213 | if (RT_FAILURE(rc))
|
---|
214 | vbcl::ipc::packet_dump(&Packet);
|
---|
215 | }
|
---|
216 | }
|
---|
217 |
|
---|
218 | return rc;
|
---|
219 | }
|
---|
220 |
|
---|
221 | int vbcl::ipc::packet_write(RTLOCALIPCSESSION hSession, vbcl::ipc::packet_t *pPacket)
|
---|
222 | {
|
---|
223 | int rc;
|
---|
224 |
|
---|
225 | AssertPtrReturn(pPacket, VERR_INVALID_PARAMETER);
|
---|
226 |
|
---|
227 | pPacket->u64Crc = 0;
|
---|
228 | pPacket->u64Crc = RTCrc64(pPacket, pPacket->cbData);
|
---|
229 |
|
---|
230 | Assert(pPacket->u64Crc);
|
---|
231 |
|
---|
232 | if (vbcl::ipc::packet_verify(pPacket, pPacket->cbData))
|
---|
233 | {
|
---|
234 | rc = RTLocalIpcSessionWrite(hSession, (void *)pPacket, pPacket->cbData);
|
---|
235 | if (RT_SUCCESS(rc))
|
---|
236 | rc = RTLocalIpcSessionFlush(hSession);
|
---|
237 | }
|
---|
238 | else
|
---|
239 | {
|
---|
240 | vbcl::ipc::packet_dump(pPacket);
|
---|
241 | rc = VERR_NOT_EQUAL;
|
---|
242 | }
|
---|
243 |
|
---|
244 | return rc;
|
---|
245 | }
|
---|
246 |
|
---|
247 | int vbcl::ipc::clipboard::ClipboardIpc::send_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
248 | {
|
---|
249 | vbcl::ipc::clipboard::formats_packet_t Packet;
|
---|
250 | SHCLFORMATS fFormats;
|
---|
251 | int rc = VINF_SUCCESS;
|
---|
252 |
|
---|
253 | RT_ZERO(Packet);
|
---|
254 |
|
---|
255 | Packet.Hdr.u64Crc = 0;
|
---|
256 | Packet.Hdr.uSessionId = uSessionId;
|
---|
257 | Packet.Hdr.idCmd = CLIP_FORMATS;
|
---|
258 | Packet.Hdr.cbData = sizeof(Packet);
|
---|
259 |
|
---|
260 | fFormats = m_fFmts.wait();
|
---|
261 | if (fFormats != m_fFmts.defaults())
|
---|
262 | {
|
---|
263 | Packet.fFormats = fFormats;
|
---|
264 | rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
|
---|
265 | }
|
---|
266 | else
|
---|
267 | rc = VERR_TIMEOUT;
|
---|
268 |
|
---|
269 | VBClLogVerbose(3, "%s: send_formats [sid=%u, fmts=0x%x], rc=%Rrc\n",
|
---|
270 | m_fServer ? "server" : "client", uSessionId, fFormats, rc);
|
---|
271 |
|
---|
272 | return rc;
|
---|
273 | }
|
---|
274 |
|
---|
275 | int vbcl::ipc::clipboard::ClipboardIpc::recv_formats(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
276 | {
|
---|
277 | int rc;
|
---|
278 | vbcl::ipc::clipboard::formats_packet_t *pPacket;
|
---|
279 | vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
|
---|
280 | SHCLFORMATS fFormats = VBOX_SHCL_FMT_NONE;
|
---|
281 |
|
---|
282 | rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
|
---|
283 | if (RT_SUCCESS(rc))
|
---|
284 | {
|
---|
285 | if ( pPacket->Hdr.idCmd == CLIP_FORMATS
|
---|
286 | && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
|
---|
287 | {
|
---|
288 | fFormats = pPacket->fFormats;
|
---|
289 | idCmd = pPacket->Hdr.idCmd;
|
---|
290 | m_fFmts.set(fFormats);
|
---|
291 | }
|
---|
292 | else
|
---|
293 | rc = VERR_WRONG_ORDER;
|
---|
294 |
|
---|
295 | RTMemFree(pPacket);
|
---|
296 | }
|
---|
297 |
|
---|
298 | VBClLogVerbose(3, "%s: recv_formats [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
|
---|
299 | m_fServer ? "server" : "client", uSessionId, idCmd, fFormats, rc);
|
---|
300 |
|
---|
301 | return rc;
|
---|
302 | }
|
---|
303 |
|
---|
304 | int vbcl::ipc::clipboard::ClipboardIpc::send_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
305 | {
|
---|
306 | vbcl::ipc::clipboard::formats_packet_t Packet;
|
---|
307 | SHCLFORMAT uFormat;
|
---|
308 | int rc = VINF_SUCCESS;
|
---|
309 |
|
---|
310 | RT_ZERO(Packet);
|
---|
311 |
|
---|
312 | Packet.Hdr.u64Crc = 0;
|
---|
313 | Packet.Hdr.uSessionId = uSessionId;
|
---|
314 | Packet.Hdr.idCmd = CLIP_FORMAT;
|
---|
315 | Packet.Hdr.cbData = sizeof(Packet);
|
---|
316 |
|
---|
317 | uFormat = m_uFmt.wait();
|
---|
318 | if (uFormat != m_uFmt.defaults())
|
---|
319 | {
|
---|
320 | Packet.fFormats = uFormat;
|
---|
321 | rc = vbcl::ipc::packet_write(hIpcSession, &Packet.Hdr);
|
---|
322 | }
|
---|
323 | else
|
---|
324 | rc = VERR_TIMEOUT;
|
---|
325 |
|
---|
326 | VBClLogVerbose(3, "%s: send_format [sid=%u, fmt=0x%x], rc=%Rrc\n",
|
---|
327 | m_fServer ? "server" : "client", uSessionId, uFormat, rc);
|
---|
328 |
|
---|
329 | return rc;
|
---|
330 | }
|
---|
331 |
|
---|
332 | int vbcl::ipc::clipboard::ClipboardIpc::recv_format(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
333 | {
|
---|
334 | int rc;
|
---|
335 | vbcl::ipc::clipboard::formats_packet_t *pPacket;
|
---|
336 | vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
|
---|
337 | SHCLFORMATS uFormat = VBOX_SHCL_FMT_NONE;
|
---|
338 |
|
---|
339 | rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
|
---|
340 | if (RT_SUCCESS(rc))
|
---|
341 | {
|
---|
342 | if ( pPacket->Hdr.idCmd == CLIP_FORMAT
|
---|
343 | && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
|
---|
344 | {
|
---|
345 | uFormat = pPacket->fFormats;
|
---|
346 | idCmd = pPacket->Hdr.idCmd;
|
---|
347 | m_uFmt.set(uFormat);
|
---|
348 | }
|
---|
349 | else
|
---|
350 | rc = VERR_WRONG_ORDER;
|
---|
351 |
|
---|
352 | RTMemFree(pPacket);
|
---|
353 | }
|
---|
354 |
|
---|
355 | VBClLogVerbose(3, "%s: recv_format [sid=%u, cmd=0x%x, fmts=0x%x], rc=%Rrc\n",
|
---|
356 | m_fServer ? "server" : "client", uSessionId, idCmd, uFormat, rc);
|
---|
357 |
|
---|
358 | return rc;
|
---|
359 | }
|
---|
360 |
|
---|
361 | int vbcl::ipc::clipboard::ClipboardIpc::send_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
362 | {
|
---|
363 | vbcl::ipc::clipboard::data_packet_t *pPacket;
|
---|
364 | int rc = VINF_SUCCESS;
|
---|
365 |
|
---|
366 | void *pvData;
|
---|
367 | uint32_t cbData;
|
---|
368 |
|
---|
369 | cbData = m_cbClipboardBuf.wait();
|
---|
370 | pvData = (void *)m_pvClipboardBuf.wait();
|
---|
371 | if ( cbData != m_cbClipboardBuf.defaults()
|
---|
372 | && pvData != (void *)m_pvClipboardBuf.defaults())
|
---|
373 | {
|
---|
374 | pPacket = (vbcl::ipc::clipboard::data_packet_t *)RTMemAllocZ(sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData);
|
---|
375 | if (RT_VALID_PTR(pPacket))
|
---|
376 | {
|
---|
377 | pPacket->Hdr.u64Crc = 0;
|
---|
378 | pPacket->Hdr.uSessionId = uSessionId;
|
---|
379 | pPacket->Hdr.idCmd = CLIP_DATA;
|
---|
380 | pPacket->Hdr.cbData = sizeof(vbcl::ipc::clipboard::data_packet_t) + cbData;
|
---|
381 | pPacket->cbData = cbData;
|
---|
382 |
|
---|
383 | memcpy((uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pvData, cbData);
|
---|
384 | rc = vbcl::ipc::packet_write(hIpcSession, &pPacket->Hdr);
|
---|
385 | RTMemFree(pPacket);
|
---|
386 | }
|
---|
387 | else
|
---|
388 | rc = VERR_NO_MEMORY;
|
---|
389 | }
|
---|
390 | else
|
---|
391 | rc = VERR_TIMEOUT;
|
---|
392 |
|
---|
393 | VBClLogVerbose(3, "%s: send_data [sid=%u, cbData=%u], rc=%Rrc\n",
|
---|
394 | m_fServer ? "server" : "client", uSessionId, cbData, rc);
|
---|
395 |
|
---|
396 | return rc;
|
---|
397 | }
|
---|
398 |
|
---|
399 | int vbcl::ipc::clipboard::ClipboardIpc::recv_data(uint32_t uSessionId, RTLOCALIPCSESSION hIpcSession)
|
---|
400 | {
|
---|
401 | int rc;
|
---|
402 | vbcl::ipc::clipboard::data_packet_t *pPacket;
|
---|
403 | vbcl::ipc::command_t idCmd = CMD_UNKNOWN;
|
---|
404 | uint32_t cbData = 0;
|
---|
405 |
|
---|
406 | rc = vbcl::ipc::packet_read(uSessionId, hIpcSession, (void **)&pPacket);
|
---|
407 | if (RT_SUCCESS(rc))
|
---|
408 | {
|
---|
409 | if ( pPacket->Hdr.idCmd == CLIP_DATA
|
---|
410 | && vbcl::ipc::packet_verify(&pPacket->Hdr, pPacket->Hdr.cbData))
|
---|
411 | {
|
---|
412 | void *pvData = RTMemAllocZ(pPacket->cbData);
|
---|
413 | idCmd = pPacket->Hdr.idCmd;
|
---|
414 | if (RT_VALID_PTR(pvData))
|
---|
415 | {
|
---|
416 | memcpy(pvData, (uint8_t *)pPacket + sizeof(vbcl::ipc::clipboard::data_packet_t), pPacket->cbData);
|
---|
417 | m_pvClipboardBuf.set((uint64_t)pvData);
|
---|
418 | cbData = pPacket->cbData;
|
---|
419 | m_cbClipboardBuf.set(cbData);
|
---|
420 | }
|
---|
421 | else
|
---|
422 | rc = VERR_NO_MEMORY;
|
---|
423 | }
|
---|
424 | else
|
---|
425 | rc = VERR_WRONG_ORDER;
|
---|
426 |
|
---|
427 | RTMemFree(pPacket);
|
---|
428 | }
|
---|
429 |
|
---|
430 | VBClLogVerbose(3, "%s: recv_data [sid=%u, cmd=0x%x, cbData=%u], rc=%Rrc\n",
|
---|
431 | m_fServer ? "server" : "client", uSessionId, idCmd, cbData, rc);
|
---|
432 |
|
---|
433 | return rc;
|
---|
434 | }
|
---|