completed pkcs7 parsing methods
[strongswan.git] / src / dumm / mconsole.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2001-2004 Jeff Dike
5 *
6 * Based on the "uml_mconsole" utility from Jeff Dike.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <sys/socket.h>
25 #include <errno.h>
26 #include <sys/un.h>
27
28 #include <debug.h>
29
30 #include "mconsole.h"
31
32 #define MCONSOLE_MAGIC 0xcafebabe
33 #define MCONSOLE_VERSION 2
34 #define MCONSOLE_MAX_DATA 512
35
36 typedef struct private_mconsole_t private_mconsole_t;
37
38 struct private_mconsole_t {
39 /** public interface */
40 mconsole_t public;
41 /** mconsole socket */
42 int console;
43 /** notify socket */
44 int notify;
45 /** address of uml socket */
46 struct sockaddr_un uml;
47 };
48
49 /**
50 * mconsole message format from "arch/um/include/mconsole.h"
51 */
52 typedef struct mconsole_request mconsole_request;
53 /** mconsole request message */
54 struct mconsole_request {
55 u_int32_t magic;
56 u_int32_t version;
57 u_int32_t len;
58 char data[MCONSOLE_MAX_DATA];
59 };
60
61
62 typedef struct mconsole_reply mconsole_reply;
63 /** mconsole reply message */
64 struct mconsole_reply {
65 u_int32_t err;
66 u_int32_t more;
67 u_int32_t len;
68 char data[MCONSOLE_MAX_DATA];
69 };
70
71 typedef struct mconsole_notify mconsole_notify;
72 /** mconsole notify message */
73 struct mconsole_notify {
74 u_int32_t magic;
75 u_int32_t version;
76 enum {
77 MCONSOLE_SOCKET,
78 MCONSOLE_PANIC,
79 MCONSOLE_HANG,
80 MCONSOLE_USER_NOTIFY,
81 } type;
82 u_int32_t len;
83 char data[MCONSOLE_MAX_DATA];
84 };
85
86 /**
87 * send a request to UML using mconsole
88 */
89 static int request(private_mconsole_t *this, char *command,
90 char buf[], size_t *size)
91 {
92 mconsole_request request;
93 mconsole_reply reply;
94 int len, total = 0;
95
96 memset(&request, 0, sizeof(request));
97 request.magic = MCONSOLE_MAGIC;
98 request.version = MCONSOLE_VERSION;
99 request.len = min(strlen(command), sizeof(reply.data) - 1);
100 strncpy(request.data, command, request.len);
101 *buf = '\0';
102 (*size)--;
103
104 if (sendto(this->console, &request, sizeof(request), 0,
105 (struct sockaddr*)&this->uml, sizeof(this->uml)) < 0)
106 {
107 snprintf(buf, *size, "sending mconsole command to UML failed: %m");
108 return -1;
109 }
110 do
111 {
112 len = recv(this->console, &reply, sizeof(reply), 0);
113 if (len < 0)
114 {
115 snprintf(buf, *size, "receiving from mconsole failed: %m");
116 return -1;
117 }
118 if (len > 0)
119 {
120 strncat(buf, reply.data, min(reply.len, *size - total));
121 total += reply.len;
122 }
123 }
124 while (reply.more);
125
126 *size = total;
127 return reply.err;
128 }
129
130 /**
131 * Implementation of mconsole_t.add_iface.
132 */
133 static bool add_iface(private_mconsole_t *this, char *guest, char *host)
134 {
135 char buf[128];
136 int len;
137
138 len = snprintf(buf, sizeof(buf), "config %s=tuntap,%s", guest, host);
139 if (len < 0 || len >= sizeof(buf))
140 {
141 return FALSE;
142 }
143 len = sizeof(buf);
144 if (request(this, buf, buf, &len) != 0)
145 {
146 DBG1("adding interface failed: %.*s", len, buf);
147 return FALSE;
148 }
149 return TRUE;
150 }
151
152 /**
153 * Implementation of mconsole_t.del_iface.
154 */
155 static bool del_iface(private_mconsole_t *this, char *guest)
156 {
157 char buf[128];
158 int len;
159
160 len = snprintf(buf, sizeof(buf), "remove %s", guest);
161 if (len < 0 || len >= sizeof(buf))
162 {
163 return FALSE;
164 }
165 if (request(this, buf, buf, &len) != 0)
166 {
167 DBG1("removing interface failed: %.*s", len, buf);
168 return FALSE;
169 }
170 return TRUE;
171 }
172
173 /**
174 * Implementation of mconsole_t.get_console_pts.
175 */
176 static char* get_console_pts(private_mconsole_t *this, int con)
177 {
178 char buf[128];
179 char *pos;
180 int len;
181
182 len = snprintf(buf, sizeof(buf), "config con%d", con);
183 if (len < 0 || len >= sizeof(buf))
184 {
185 return NULL;
186 }
187 len = sizeof(buf);
188 if (request(this, buf, buf, &len) != 0)
189 {
190 DBG1("getting console pts failed: %.*s", len, buf);
191 return NULL;
192 }
193 pos = memchr(buf, ':', len);
194 if (pos == NULL)
195 {
196 return NULL;
197 }
198 pos++;
199 return strndup(pos, len - (pos - buf));
200 }
201
202 /**
203 * Poll until guest is ready
204 */
205 static bool wait_bootup(private_mconsole_t *this)
206 {
207 char *cmd, buf[128];
208 int len, res;
209
210 cmd = "config con0";
211 while (TRUE)
212 {
213 len = sizeof(buf);
214 res = request(this, cmd, buf, &len);
215 if (res < 0)
216 {
217 return FALSE;
218 }
219 if (res == 0)
220 {
221 return TRUE;
222 }
223 usleep(50000);
224 }
225 }
226
227 /**
228 * Implementation of mconsole_t.destroy.
229 */
230 static void destroy(private_mconsole_t *this)
231 {
232 close(this->console);
233 close(this->notify);
234 free(this);
235 }
236
237 /**
238 * setup the mconsole notify connection and wait for its readyness
239 */
240 static bool wait_for_notify(private_mconsole_t *this, char *nsock)
241 {
242 struct sockaddr_un addr;
243 mconsole_notify notify;
244 int len;
245
246 this->notify = socket(AF_UNIX, SOCK_DGRAM, 0);
247 if (this->notify < 0)
248 {
249 DBG1("opening mconsole notify socket failed: %m");
250 return FALSE;
251 }
252 memset(&addr, 0, sizeof(addr));
253 addr.sun_family = AF_UNIX;
254 strncpy(addr.sun_path, nsock, sizeof(addr));
255 if (bind(this->notify, (struct sockaddr*)&addr, sizeof(addr)) < 0)
256 {
257 DBG1("binding mconsole notify socket to '%s' failed: %m", nsock);
258 close(this->notify);
259 return FALSE;
260 }
261 do
262 {
263 len = recvfrom(this->notify, &notify, sizeof(notify), 0, NULL, 0);
264 } while (len < 0 && errno == EINTR);
265 if (len < 0 || len >= sizeof(notify))
266 {
267 DBG1("reading from mconsole notify socket failed: %m");
268 close(this->notify);
269 unlink(nsock);
270 return FALSE;
271 }
272 if (notify.magic != MCONSOLE_MAGIC ||
273 notify.version != MCONSOLE_VERSION ||
274 notify.type != MCONSOLE_SOCKET)
275 {
276 DBG1("received unexpected message from mconsole notify socket: %b",
277 &notify, sizeof(notify));
278 close(this->notify);
279 unlink(nsock);
280 return FALSE;
281 }
282 memset(&this->uml, 0, sizeof(this->uml));
283 this->uml.sun_family = AF_UNIX;
284 strncpy(this->uml.sun_path, (char*)&notify.data, sizeof(this->uml.sun_path));
285 return TRUE;
286 }
287
288 /**
289 * setup the mconsole console connection
290 */
291 static bool setup_console(private_mconsole_t *this)
292 {
293 struct sockaddr_un addr;
294
295 this->console = socket(AF_UNIX, SOCK_DGRAM, 0);
296 if (this->console < 0)
297 {
298 DBG1("opening mconsole socket failed: %m");
299 return FALSE;
300 }
301 memset(&addr, 0, sizeof(addr));
302 addr.sun_family = AF_UNIX;
303 snprintf(&addr.sun_path[1], sizeof(addr.sun_path), "%5d-%d",
304 getpid(), this->console);
305 if (bind(this->console, (struct sockaddr*)&addr, sizeof(addr)) < 0)
306 {
307 DBG1("binding mconsole socket to '%s' failed: %m", &addr.sun_path[1]);
308 close(this->console);
309 return FALSE;
310 }
311 return TRUE;
312 }
313
314 /**
315 * create the mconsole instance
316 */
317 mconsole_t *mconsole_create(char *notify)
318 {
319 private_mconsole_t *this = malloc_thing(private_mconsole_t);
320
321 this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface;
322 this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
323 this->public.get_console_pts = (char*(*)(mconsole_t*, int con))get_console_pts;
324 this->public.destroy = (void*)destroy;
325
326 if (!wait_for_notify(this, notify))
327 {
328 free(this);
329 return NULL;
330 }
331
332 if (!setup_console(this))
333 {
334 close(this->notify);
335 unlink(notify);
336 free(this);
337 return NULL;
338 }
339 unlink(notify);
340
341 if (!wait_bootup(this))
342 {
343 destroy(this);
344 return NULL;
345 }
346
347 return &this->public;
348 }
349