summaryrefslogtreecommitdiffstats
path: root/src/syslog_relay.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/syslog_relay.c')
-rw-r--r--src/syslog_relay.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/syslog_relay.c b/src/syslog_relay.c
new file mode 100644
index 0000000..9f4296e
--- /dev/null
+++ b/src/syslog_relay.c
@@ -0,0 +1,248 @@
1/*
2 * syslog_relay.c
3 * com.apple.syslog_relay service implementation.
4 *
5 * Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
6 * Copyright (c) 2013-2015 Martin Szulecki, All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26#include <string.h>
27#include <stdlib.h>
28
29#include "syslog_relay.h"
30#include "lockdown.h"
31#include "common/debug.h"
32
33struct syslog_relay_worker_thread {
34 syslog_relay_client_t client;
35 syslog_relay_receive_cb_t cbfunc;
36 void *user_data;
37 int is_raw;
38};
39
40/**
41 * Convert a service_error_t value to a syslog_relay_error_t value.
42 * Used internally to get correct error codes.
43 *
44 * @param err An service_error_t error code
45 *
46 * @return A matching syslog_relay_error_t error code,
47 * SYSLOG_RELAY_E_UNKNOWN_ERROR otherwise.
48 */
49static syslog_relay_error_t syslog_relay_error(service_error_t err)
50{
51 switch (err) {
52 case SERVICE_E_SUCCESS:
53 return SYSLOG_RELAY_E_SUCCESS;
54 case SERVICE_E_INVALID_ARG:
55 return SYSLOG_RELAY_E_INVALID_ARG;
56 case SERVICE_E_MUX_ERROR:
57 return SYSLOG_RELAY_E_MUX_ERROR;
58 case SERVICE_E_SSL_ERROR:
59 return SYSLOG_RELAY_E_SSL_ERROR;
60 case SERVICE_E_NOT_ENOUGH_DATA:
61 return SYSLOG_RELAY_E_NOT_ENOUGH_DATA;
62 case SERVICE_E_TIMEOUT:
63 return SYSLOG_RELAY_E_TIMEOUT;
64 default:
65 break;
66 }
67 return SYSLOG_RELAY_E_UNKNOWN_ERROR;
68}
69
70syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client)
71{
72 *client = NULL;
73
74 if (!device || !service || service->port == 0 || !client || *client) {
75 debug_info("Incorrect parameter passed to syslog_relay_client_new.");
76 return SYSLOG_RELAY_E_INVALID_ARG;
77 }
78
79 debug_info("Creating syslog_relay_client, port = %d.", service->port);
80
81 service_client_t parent = NULL;
82 syslog_relay_error_t ret = syslog_relay_error(service_client_new(device, service, &parent));
83 if (ret != SYSLOG_RELAY_E_SUCCESS) {
84 debug_info("Creating base service client failed. Error: %i", ret);
85 return ret;
86 }
87
88 syslog_relay_client_t client_loc = (syslog_relay_client_t) malloc(sizeof(struct syslog_relay_client_private));
89 client_loc->parent = parent;
90 client_loc->worker = THREAD_T_NULL;
91
92 *client = client_loc;
93
94 debug_info("syslog_relay_client successfully created.");
95 return 0;
96}
97
98syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label)
99{
100 syslog_relay_error_t err = SYSLOG_RELAY_E_UNKNOWN_ERROR;
101 service_client_factory_start_service(device, SYSLOG_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(syslog_relay_client_new), &err);
102 return err;
103}
104
105syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client)
106{
107 if (!client)
108 return SYSLOG_RELAY_E_INVALID_ARG;
109 syslog_relay_stop_capture(client);
110 syslog_relay_error_t err = syslog_relay_error(service_client_free(client->parent));
111 free(client);
112
113 return err;
114}
115
116syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received)
117{
118 return syslog_relay_receive_with_timeout(client, data, size, received, 1000);
119}
120
121syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
122{
123 syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR;
124 int bytes = 0;
125
126 if (!client || !data || (size == 0)) {
127 return SYSLOG_RELAY_E_INVALID_ARG;
128 }
129
130 res = syslog_relay_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
131 if (res != SYSLOG_RELAY_E_SUCCESS && res != SYSLOG_RELAY_E_TIMEOUT && res != SYSLOG_RELAY_E_NOT_ENOUGH_DATA) {
132 debug_info("Could not read data, error %d", res);
133 }
134 if (received) {
135 *received = (uint32_t)bytes;
136 }
137
138 return res;
139}
140
141void *syslog_relay_worker(void *arg)
142{
143 syslog_relay_error_t ret = SYSLOG_RELAY_E_UNKNOWN_ERROR;
144 struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)arg;
145
146 if (!srwt)
147 return NULL;
148
149 debug_info("Running");
150
151 while (srwt->client->parent) {
152 char c;
153 uint32_t bytes = 0;
154 ret = syslog_relay_receive_with_timeout(srwt->client, &c, 1, &bytes, 100);
155 if (ret == SYSLOG_RELAY_E_TIMEOUT || ret == SYSLOG_RELAY_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == SYSLOG_RELAY_E_SUCCESS))) {
156 continue;
157 }
158 if (ret < 0) {
159 debug_info("Connection to syslog relay interrupted");
160 break;
161 }
162 if (srwt->is_raw) {
163 srwt->cbfunc(c, srwt->user_data);
164 } else if (c != 0) {
165 srwt->cbfunc(c, srwt->user_data);
166 }
167 }
168
169 if (srwt) {
170 free(srwt);
171 }
172
173 debug_info("Exiting");
174
175 return NULL;
176}
177
178syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
179{
180 if (!client || !callback)
181 return SYSLOG_RELAY_E_INVALID_ARG;
182
183 syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR;
184
185 if (client->worker) {
186 debug_info("Another syslog capture thread appears to be running already.");
187 return res;
188 }
189
190 /* start worker thread */
191 struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)malloc(sizeof(struct syslog_relay_worker_thread));
192 if (srwt) {
193 srwt->client = client;
194 srwt->cbfunc = callback;
195 srwt->user_data = user_data;
196 srwt->is_raw = 0;
197
198 if (thread_new(&client->worker, syslog_relay_worker, srwt) == 0) {
199 res = SYSLOG_RELAY_E_SUCCESS;
200 }
201 }
202
203 return res;
204}
205
206syslog_relay_error_t syslog_relay_start_capture_raw(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data)
207{
208 if (!client || !callback)
209 return SYSLOG_RELAY_E_INVALID_ARG;
210
211 syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR;
212
213 if (client->worker) {
214 debug_info("Another syslog capture thread appears to be running already.");
215 return res;
216 }
217
218 /* start worker thread */
219 struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)malloc(sizeof(struct syslog_relay_worker_thread));
220 if (srwt) {
221 srwt->client = client;
222 srwt->cbfunc = callback;
223 srwt->user_data = user_data;
224 srwt->is_raw = 1;
225
226 if (thread_new(&client->worker, syslog_relay_worker, srwt) == 0) {
227 res = SYSLOG_RELAY_E_SUCCESS;
228 }
229 }
230
231 return res;
232}
233
234syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client)
235{
236 if (client->worker) {
237 /* notify thread to finish */
238 service_client_t parent = client->parent;
239 client->parent = NULL;
240 /* join thread to make it exit */
241 thread_join(client->worker);
242 thread_free(client->worker);
243 client->worker = THREAD_T_NULL;
244 client->parent = parent;
245 }
246
247 return SYSLOG_RELAY_E_SUCCESS;
248}