PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/gio/gunixconnection.c

https://gitlab.com/ImageMagick/glib
C | 702 lines | 388 code | 74 blank | 240 comment | 49 complexity | b95079629fe4c1c7526dd80b265e30b1 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0
  1. /* GIO - GLib Input, Output and Streaming Library
  2. *
  3. * Copyright © 2009 Codethink Limited
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * See the included COPYING file for more information.
  11. *
  12. * Authors: Ryan Lortie <desrt@desrt.ca>
  13. */
  14. #include "config.h"
  15. #include "gunixconnection.h"
  16. #include "gnetworking.h"
  17. #include "gsocket.h"
  18. #include "gsocketcontrolmessage.h"
  19. #include "gunixcredentialsmessage.h"
  20. #include "gunixfdmessage.h"
  21. #include "glibintl.h"
  22. #include <errno.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. /**
  26. * SECTION:gunixconnection
  27. * @title: GUnixConnection
  28. * @short_description: A UNIX domain GSocketConnection
  29. * @include: gio/gunixconnection.h
  30. * @see_also: #GSocketConnection.
  31. *
  32. * This is the subclass of #GSocketConnection that is created
  33. * for UNIX domain sockets.
  34. *
  35. * It contains functions to do some of the UNIX socket specific
  36. * functionality like passing file descriptors.
  37. *
  38. * Note that `<gio/gunixconnection.h>` belongs to the UNIX-specific
  39. * GIO interfaces, thus you have to use the `gio-unix-2.0.pc`
  40. * pkg-config file when using it.
  41. *
  42. * Since: 2.22
  43. */
  44. /**
  45. * GUnixConnection:
  46. *
  47. * #GUnixConnection is an opaque data structure and can only be accessed
  48. * using the following functions.
  49. **/
  50. G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection,
  51. G_TYPE_SOCKET_CONNECTION,
  52. g_socket_connection_factory_register_type (g_define_type_id,
  53. G_SOCKET_FAMILY_UNIX,
  54. G_SOCKET_TYPE_STREAM,
  55. G_SOCKET_PROTOCOL_DEFAULT);
  56. );
  57. /**
  58. * g_unix_connection_send_fd:
  59. * @connection: a #GUnixConnection
  60. * @fd: a file descriptor
  61. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
  62. * @error: (nullable): #GError for error reporting, or %NULL to ignore.
  63. *
  64. * Passes a file descriptor to the receiving side of the
  65. * connection. The receiving end has to call g_unix_connection_receive_fd()
  66. * to accept the file descriptor.
  67. *
  68. * As well as sending the fd this also writes a single byte to the
  69. * stream, as this is required for fd passing to work on some
  70. * implementations.
  71. *
  72. * Returns: a %TRUE on success, %NULL on error.
  73. *
  74. * Since: 2.22
  75. */
  76. gboolean
  77. g_unix_connection_send_fd (GUnixConnection *connection,
  78. gint fd,
  79. GCancellable *cancellable,
  80. GError **error)
  81. {
  82. GSocketControlMessage *scm;
  83. GSocket *socket;
  84. g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
  85. g_return_val_if_fail (fd >= 0, FALSE);
  86. scm = g_unix_fd_message_new ();
  87. if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
  88. {
  89. g_object_unref (scm);
  90. return FALSE;
  91. }
  92. g_object_get (connection, "socket", &socket, NULL);
  93. if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1)
  94. /* XXX could it 'fail' with zero? */
  95. {
  96. g_object_unref (socket);
  97. g_object_unref (scm);
  98. return FALSE;
  99. }
  100. g_object_unref (socket);
  101. g_object_unref (scm);
  102. return TRUE;
  103. }
  104. /**
  105. * g_unix_connection_receive_fd:
  106. * @connection: a #GUnixConnection
  107. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
  108. * @error: (nullable): #GError for error reporting, or %NULL to ignore
  109. *
  110. * Receives a file descriptor from the sending end of the connection.
  111. * The sending end has to call g_unix_connection_send_fd() for this
  112. * to work.
  113. *
  114. * As well as reading the fd this also reads a single byte from the
  115. * stream, as this is required for fd passing to work on some
  116. * implementations.
  117. *
  118. * Returns: a file descriptor on success, -1 on error.
  119. *
  120. * Since: 2.22
  121. **/
  122. gint
  123. g_unix_connection_receive_fd (GUnixConnection *connection,
  124. GCancellable *cancellable,
  125. GError **error)
  126. {
  127. GSocketControlMessage **scms;
  128. gint *fds, nfd, fd, nscm;
  129. GUnixFDMessage *fdmsg;
  130. GSocket *socket;
  131. g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
  132. g_object_get (connection, "socket", &socket, NULL);
  133. if (g_socket_receive_message (socket, NULL, NULL, 0,
  134. &scms, &nscm, NULL, cancellable, error) != 1)
  135. /* XXX it _could_ 'fail' with zero. */
  136. {
  137. g_object_unref (socket);
  138. return -1;
  139. }
  140. g_object_unref (socket);
  141. if (nscm != 1)
  142. {
  143. gint i;
  144. g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
  145. ngettext("Expecting 1 control message, got %d",
  146. "Expecting 1 control message, got %d",
  147. nscm),
  148. nscm);
  149. for (i = 0; i < nscm; i++)
  150. g_object_unref (scms[i]);
  151. g_free (scms);
  152. return -1;
  153. }
  154. if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
  155. {
  156. g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
  157. _("Unexpected type of ancillary data"));
  158. g_object_unref (scms[0]);
  159. g_free (scms);
  160. return -1;
  161. }
  162. fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
  163. g_free (scms);
  164. fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
  165. g_object_unref (fdmsg);
  166. if (nfd != 1)
  167. {
  168. gint i;
  169. g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
  170. ngettext("Expecting one fd, but got %d\n",
  171. "Expecting one fd, but got %d\n",
  172. nfd),
  173. nfd);
  174. for (i = 0; i < nfd; i++)
  175. close (fds[i]);
  176. g_free (fds);
  177. return -1;
  178. }
  179. fd = *fds;
  180. g_free (fds);
  181. if (fd < 0)
  182. {
  183. g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
  184. _("Received invalid fd"));
  185. fd = -1;
  186. }
  187. return fd;
  188. }
  189. static void
  190. g_unix_connection_init (GUnixConnection *connection)
  191. {
  192. }
  193. static void
  194. g_unix_connection_class_init (GUnixConnectionClass *class)
  195. {
  196. }
  197. /* TODO: Other stuff we might want to add are:
  198. void g_unix_connection_send_fd_async (GUnixConnection *connection,
  199. gint fd,
  200. gboolean close,
  201. gint io_priority,
  202. GAsyncReadyCallback callback,
  203. gpointer user_data);
  204. gboolean g_unix_connection_send_fd_finish (GUnixConnection *connection,
  205. GError **error);
  206. gboolean g_unix_connection_send_fds (GUnixConnection *connection,
  207. gint *fds,
  208. gint nfds,
  209. GError **error);
  210. void g_unix_connection_send_fds_async (GUnixConnection *connection,
  211. gint *fds,
  212. gint nfds,
  213. gint io_priority,
  214. GAsyncReadyCallback callback,
  215. gpointer user_data);
  216. gboolean g_unix_connection_send_fds_finish (GUnixConnection *connection,
  217. GError **error);
  218. void g_unix_connection_receive_fd_async (GUnixConnection *connection,
  219. gint io_priority,
  220. GAsyncReadyCallback callback,
  221. gpointer user_data);
  222. gint g_unix_connection_receive_fd_finish (GUnixConnection *connection,
  223. GError **error);
  224. gboolean g_unix_connection_send_fake_credentials (GUnixConnection *connection,
  225. guint64 pid,
  226. guint64 uid,
  227. guint64 gid,
  228. GError **error);
  229. void g_unix_connection_send_fake_credentials_async (GUnixConnection *connection,
  230. guint64 pid,
  231. guint64 uid,
  232. guint64 gid,
  233. gint io_priority,
  234. GAsyncReadyCallback callback,
  235. gpointer user_data);
  236. gboolean g_unix_connection_send_fake_credentials_finish (GUnixConnection *connection,
  237. GError **error);
  238. gboolean g_unix_connection_create_pair (GUnixConnection **one,
  239. GUnixConnection **two,
  240. GError **error);
  241. */
  242. /**
  243. * g_unix_connection_send_credentials:
  244. * @connection: A #GUnixConnection.
  245. * @cancellable: (nullable): A #GCancellable or %NULL.
  246. * @error: Return location for error or %NULL.
  247. *
  248. * Passes the credentials of the current user the receiving side
  249. * of the connection. The receiving end has to call
  250. * g_unix_connection_receive_credentials() (or similar) to accept the
  251. * credentials.
  252. *
  253. * As well as sending the credentials this also writes a single NUL
  254. * byte to the stream, as this is required for credentials passing to
  255. * work on some implementations.
  256. *
  257. * Other ways to exchange credentials with a foreign peer includes the
  258. * #GUnixCredentialsMessage type and g_socket_get_credentials() function.
  259. *
  260. * Returns: %TRUE on success, %FALSE if @error is set.
  261. *
  262. * Since: 2.26
  263. */
  264. gboolean
  265. g_unix_connection_send_credentials (GUnixConnection *connection,
  266. GCancellable *cancellable,
  267. GError **error)
  268. {
  269. GCredentials *credentials;
  270. GSocketControlMessage *scm;
  271. GSocket *socket;
  272. gboolean ret;
  273. GOutputVector vector;
  274. guchar nul_byte[1] = {'\0'};
  275. gint num_messages;
  276. g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
  277. g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
  278. ret = FALSE;
  279. credentials = g_credentials_new ();
  280. vector.buffer = &nul_byte;
  281. vector.size = 1;
  282. if (g_unix_credentials_message_is_supported ())
  283. {
  284. scm = g_unix_credentials_message_new_with_credentials (credentials);
  285. num_messages = 1;
  286. }
  287. else
  288. {
  289. scm = NULL;
  290. num_messages = 0;
  291. }
  292. g_object_get (connection, "socket", &socket, NULL);
  293. if (g_socket_send_message (socket,
  294. NULL, /* address */
  295. &vector,
  296. 1,
  297. &scm,
  298. num_messages,
  299. G_SOCKET_MSG_NONE,
  300. cancellable,
  301. error) != 1)
  302. {
  303. g_prefix_error (error, _("Error sending credentials: "));
  304. goto out;
  305. }
  306. ret = TRUE;
  307. out:
  308. g_object_unref (socket);
  309. if (scm != NULL)
  310. g_object_unref (scm);
  311. g_object_unref (credentials);
  312. return ret;
  313. }
  314. static void
  315. send_credentials_async_thread (GTask *task,
  316. gpointer source_object,
  317. gpointer task_data,
  318. GCancellable *cancellable)
  319. {
  320. GError *error = NULL;
  321. if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object),
  322. cancellable,
  323. &error))
  324. g_task_return_boolean (task, TRUE);
  325. else
  326. g_task_return_error (task, error);
  327. g_object_unref (task);
  328. }
  329. /**
  330. * g_unix_connection_send_credentials_async:
  331. * @connection: A #GUnixConnection.
  332. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
  333. * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
  334. * @user_data: (closure): the data to pass to callback function
  335. *
  336. * Asynchronously send credentials.
  337. *
  338. * For more details, see g_unix_connection_send_credentials() which is
  339. * the synchronous version of this call.
  340. *
  341. * When the operation is finished, @callback will be called. You can then call
  342. * g_unix_connection_send_credentials_finish() to get the result of the operation.
  343. *
  344. * Since: 2.32
  345. **/
  346. void
  347. g_unix_connection_send_credentials_async (GUnixConnection *connection,
  348. GCancellable *cancellable,
  349. GAsyncReadyCallback callback,
  350. gpointer user_data)
  351. {
  352. GTask *task;
  353. task = g_task_new (connection, cancellable, callback, user_data);
  354. g_task_set_source_tag (task, g_unix_connection_send_credentials_async);
  355. g_task_run_in_thread (task, send_credentials_async_thread);
  356. }
  357. /**
  358. * g_unix_connection_send_credentials_finish:
  359. * @connection: A #GUnixConnection.
  360. * @result: a #GAsyncResult.
  361. * @error: a #GError, or %NULL
  362. *
  363. * Finishes an asynchronous send credentials operation started with
  364. * g_unix_connection_send_credentials_async().
  365. *
  366. * Returns: %TRUE if the operation was successful, otherwise %FALSE.
  367. *
  368. * Since: 2.32
  369. **/
  370. gboolean
  371. g_unix_connection_send_credentials_finish (GUnixConnection *connection,
  372. GAsyncResult *result,
  373. GError **error)
  374. {
  375. g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
  376. return g_task_propagate_boolean (G_TASK (result), error);
  377. }
  378. /**
  379. * g_unix_connection_receive_credentials:
  380. * @connection: A #GUnixConnection.
  381. * @cancellable: (nullable): A #GCancellable or %NULL.
  382. * @error: Return location for error or %NULL.
  383. *
  384. * Receives credentials from the sending end of the connection. The
  385. * sending end has to call g_unix_connection_send_credentials() (or
  386. * similar) for this to work.
  387. *
  388. * As well as reading the credentials this also reads (and discards) a
  389. * single byte from the stream, as this is required for credentials
  390. * passing to work on some implementations.
  391. *
  392. * Other ways to exchange credentials with a foreign peer includes the
  393. * #GUnixCredentialsMessage type and g_socket_get_credentials() function.
  394. *
  395. * Returns: (transfer full): Received credentials on success (free with
  396. * g_object_unref()), %NULL if @error is set.
  397. *
  398. * Since: 2.26
  399. */
  400. GCredentials *
  401. g_unix_connection_receive_credentials (GUnixConnection *connection,
  402. GCancellable *cancellable,
  403. GError **error)
  404. {
  405. GCredentials *ret;
  406. GSocketControlMessage **scms;
  407. gint nscm;
  408. GSocket *socket;
  409. gint n;
  410. gssize num_bytes_read;
  411. #ifdef __linux__
  412. gboolean turn_off_so_passcreds;
  413. #endif
  414. g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL);
  415. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  416. ret = NULL;
  417. scms = NULL;
  418. g_object_get (connection, "socket", &socket, NULL);
  419. /* On Linux, we need to turn on SO_PASSCRED if it isn't enabled
  420. * already. We also need to turn it off when we're done. See
  421. * #617483 for more discussion.
  422. */
  423. #ifdef __linux__
  424. {
  425. gint opt_val;
  426. turn_off_so_passcreds = FALSE;
  427. opt_val = 0;
  428. if (!g_socket_get_option (socket,
  429. SOL_SOCKET,
  430. SO_PASSCRED,
  431. &opt_val,
  432. NULL))
  433. {
  434. int errsv = errno;
  435. g_set_error (error,
  436. G_IO_ERROR,
  437. g_io_error_from_errno (errsv),
  438. _("Error checking if SO_PASSCRED is enabled for socket: %s"),
  439. g_strerror (errsv));
  440. goto out;
  441. }
  442. if (opt_val == 0)
  443. {
  444. if (!g_socket_set_option (socket,
  445. SOL_SOCKET,
  446. SO_PASSCRED,
  447. TRUE,
  448. NULL))
  449. {
  450. int errsv = errno;
  451. g_set_error (error,
  452. G_IO_ERROR,
  453. g_io_error_from_errno (errsv),
  454. _("Error enabling SO_PASSCRED: %s"),
  455. g_strerror (errsv));
  456. goto out;
  457. }
  458. turn_off_so_passcreds = TRUE;
  459. }
  460. }
  461. #endif
  462. g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE);
  463. num_bytes_read = g_socket_receive_message (socket,
  464. NULL, /* GSocketAddress **address */
  465. NULL,
  466. 0,
  467. &scms,
  468. &nscm,
  469. NULL,
  470. cancellable,
  471. error);
  472. if (num_bytes_read != 1)
  473. {
  474. /* Handle situation where g_socket_receive_message() returns
  475. * 0 bytes and not setting @error
  476. */
  477. if (num_bytes_read == 0 && error != NULL && *error == NULL)
  478. {
  479. g_set_error_literal (error,
  480. G_IO_ERROR,
  481. G_IO_ERROR_FAILED,
  482. _("Expecting to read a single byte for receiving credentials but read zero bytes"));
  483. }
  484. goto out;
  485. }
  486. if (g_unix_credentials_message_is_supported () &&
  487. /* Fall back on get_credentials if the other side didn't send the credentials */
  488. nscm > 0)
  489. {
  490. if (nscm != 1)
  491. {
  492. g_set_error (error,
  493. G_IO_ERROR,
  494. G_IO_ERROR_FAILED,
  495. ngettext("Expecting 1 control message, got %d",
  496. "Expecting 1 control message, got %d",
  497. nscm),
  498. nscm);
  499. goto out;
  500. }
  501. if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
  502. {
  503. g_set_error_literal (error,
  504. G_IO_ERROR,
  505. G_IO_ERROR_FAILED,
  506. _("Unexpected type of ancillary data"));
  507. goto out;
  508. }
  509. ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
  510. g_object_ref (ret);
  511. }
  512. else
  513. {
  514. if (nscm != 0)
  515. {
  516. g_set_error (error,
  517. G_IO_ERROR,
  518. G_IO_ERROR_FAILED,
  519. _("Not expecting control message, but got %d"),
  520. nscm);
  521. goto out;
  522. }
  523. else
  524. {
  525. ret = g_socket_get_credentials (socket, error);
  526. }
  527. }
  528. out:
  529. #ifdef __linux__
  530. if (turn_off_so_passcreds)
  531. {
  532. if (!g_socket_set_option (socket,
  533. SOL_SOCKET,
  534. SO_PASSCRED,
  535. FALSE,
  536. NULL))
  537. {
  538. int errsv = errno;
  539. g_set_error (error,
  540. G_IO_ERROR,
  541. g_io_error_from_errno (errsv),
  542. _("Error while disabling SO_PASSCRED: %s"),
  543. g_strerror (errsv));
  544. goto out;
  545. }
  546. }
  547. #endif
  548. if (scms != NULL)
  549. {
  550. for (n = 0; n < nscm; n++)
  551. g_object_unref (scms[n]);
  552. g_free (scms);
  553. }
  554. g_object_unref (socket);
  555. return ret;
  556. }
  557. static void
  558. receive_credentials_async_thread (GTask *task,
  559. gpointer source_object,
  560. gpointer task_data,
  561. GCancellable *cancellable)
  562. {
  563. GCredentials *creds;
  564. GError *error = NULL;
  565. creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object),
  566. cancellable,
  567. &error);
  568. if (creds)
  569. g_task_return_pointer (task, creds, g_object_unref);
  570. else
  571. g_task_return_error (task, error);
  572. g_object_unref (task);
  573. }
  574. /**
  575. * g_unix_connection_receive_credentials_async:
  576. * @connection: A #GUnixConnection.
  577. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
  578. * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
  579. * @user_data: (closure): the data to pass to callback function
  580. *
  581. * Asynchronously receive credentials.
  582. *
  583. * For more details, see g_unix_connection_receive_credentials() which is
  584. * the synchronous version of this call.
  585. *
  586. * When the operation is finished, @callback will be called. You can then call
  587. * g_unix_connection_receive_credentials_finish() to get the result of the operation.
  588. *
  589. * Since: 2.32
  590. **/
  591. void
  592. g_unix_connection_receive_credentials_async (GUnixConnection *connection,
  593. GCancellable *cancellable,
  594. GAsyncReadyCallback callback,
  595. gpointer user_data)
  596. {
  597. GTask *task;
  598. task = g_task_new (connection, cancellable, callback, user_data);
  599. g_task_set_source_tag (task, g_unix_connection_receive_credentials_async);
  600. g_task_run_in_thread (task, receive_credentials_async_thread);
  601. }
  602. /**
  603. * g_unix_connection_receive_credentials_finish:
  604. * @connection: A #GUnixConnection.
  605. * @result: a #GAsyncResult.
  606. * @error: a #GError, or %NULL
  607. *
  608. * Finishes an asynchronous receive credentials operation started with
  609. * g_unix_connection_receive_credentials_async().
  610. *
  611. * Returns: (transfer full): a #GCredentials, or %NULL on error.
  612. * Free the returned object with g_object_unref().
  613. *
  614. * Since: 2.32
  615. **/
  616. GCredentials *
  617. g_unix_connection_receive_credentials_finish (GUnixConnection *connection,
  618. GAsyncResult *result,
  619. GError **error)
  620. {
  621. g_return_val_if_fail (g_task_is_valid (result, connection), NULL);
  622. return g_task_propagate_pointer (G_TASK (result), error);
  623. }