/src/p11-kit/p11-kit/rpc-transport.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2012 Stefan Walter |
3 | | * Copyright (C) 2013 Red Hat Inc. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * |
9 | | * * Redistributions of source code must retain the above |
10 | | * copyright notice, this list of conditions and the |
11 | | * following disclaimer. |
12 | | * * Redistributions in binary form must reproduce the |
13 | | * above copyright notice, this list of conditions and |
14 | | * the following disclaimer in the documentation and/or |
15 | | * other materials provided with the distribution. |
16 | | * * The names of contributors to this software may not be |
17 | | * used to endorse or promote products derived from this |
18 | | * software without specific prior written permission. |
19 | | * |
20 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
23 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
24 | | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
25 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
26 | | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
27 | | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
28 | | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
29 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
30 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
31 | | * DAMAGE. |
32 | | * |
33 | | * Author: Stef Walter <stefw@gnome.org> |
34 | | */ |
35 | | |
36 | | #include "config.h" |
37 | | |
38 | | #include "argv.h" |
39 | | #include "compat.h" |
40 | 0 | #define P11_DEBUG_FLAG P11_DEBUG_RPC |
41 | | #include "debug.h" |
42 | | #include "message.h" |
43 | | #include "pkcs11.h" |
44 | | #include "private.h" |
45 | | #include "rpc.h" |
46 | | #include "rpc-message.h" |
47 | | #include "path.h" |
48 | | |
49 | | #include <sys/types.h> |
50 | | |
51 | | #include <assert.h> |
52 | | #include <errno.h> |
53 | | #include <fcntl.h> |
54 | | #include <stdint.h> |
55 | | #include <stdio.h> |
56 | | #include <stdlib.h> |
57 | | #include <string.h> |
58 | | |
59 | | #ifdef OS_UNIX |
60 | | #include <sys/select.h> |
61 | | #include <sys/socket.h> |
62 | | #include <sys/wait.h> |
63 | | #include <sys/un.h> |
64 | | #include <signal.h> |
65 | | #include <unistd.h> |
66 | | #include <limits.h> |
67 | | #endif |
68 | | |
69 | | #ifdef OS_WIN32 |
70 | | #include <process.h> |
71 | | #include <signal.h> |
72 | | #include <winsock2.h> |
73 | | #ifndef EWOULDBLOCK |
74 | | #define EWOULDBLOCK WSAEWOULDBLOCK |
75 | | #endif |
76 | | #endif |
77 | | |
78 | | #ifndef EPROTO |
79 | | #define EPROTO EIO |
80 | | #endif |
81 | | |
82 | | #ifdef ENABLE_NLS |
83 | | #include <libintl.h> |
84 | 0 | #define _(x) dgettext(PACKAGE_NAME, x) |
85 | | #else |
86 | | #define _(x) (x) |
87 | | #endif |
88 | | |
89 | | typedef struct { |
90 | | /* Never changes. On Unix, these are identical, as it is |
91 | | * backed by a socket. On Windows, it is another file |
92 | | * descriptor, as they are backed by two pipes */ |
93 | | int read_fd; |
94 | | int write_fd; |
95 | | |
96 | | /* Protected by the lock */ |
97 | | p11_mutex_t write_lock; |
98 | | int refs; |
99 | | int last_code; |
100 | | |
101 | | /* This data is protected by read mutex */ |
102 | | p11_mutex_t read_lock; |
103 | | #ifdef OS_UNIX |
104 | | /* Signalled when read_code changes */ |
105 | | p11_cond_t read_code_cond; |
106 | | #endif |
107 | | uint32_t read_code; |
108 | | uint32_t read_olen; |
109 | | uint32_t read_dlen; |
110 | | } rpc_socket; |
111 | | |
112 | | static rpc_socket * |
113 | | rpc_socket_new (int fd) |
114 | 0 | { |
115 | 0 | rpc_socket *sock; |
116 | |
|
117 | 0 | sock = calloc (1, sizeof (rpc_socket)); |
118 | 0 | return_val_if_fail (sock != NULL, NULL); |
119 | | |
120 | 0 | sock->read_fd = fd; |
121 | 0 | sock->write_fd = fd; |
122 | 0 | sock->last_code = 0x10; |
123 | 0 | sock->refs = 1; |
124 | |
|
125 | 0 | p11_mutex_init (&sock->write_lock); |
126 | 0 | p11_mutex_init (&sock->read_lock); |
127 | |
|
128 | 0 | #ifdef OS_UNIX |
129 | 0 | p11_cond_init (&sock->read_code_cond); |
130 | 0 | #endif |
131 | |
|
132 | 0 | return sock; |
133 | 0 | } |
134 | | |
135 | | #if 0 |
136 | | static rpc_socket * |
137 | | rpc_socket_ref (rpc_socket *sock) |
138 | | { |
139 | | assert (sock != NULL); |
140 | | |
141 | | p11_mutex_lock (&sock->write_lock); |
142 | | sock->refs++; |
143 | | p11_mutex_unlock (&sock->write_lock); |
144 | | |
145 | | return sock; |
146 | | } |
147 | | |
148 | | static bool |
149 | | rpc_socket_is_open (rpc_socket *sock) |
150 | | { |
151 | | assert (sock != NULL); |
152 | | return sock->read_fd >= 0; |
153 | | } |
154 | | #endif |
155 | | |
156 | | static void |
157 | | rpc_socket_close (rpc_socket *sock) |
158 | 0 | { |
159 | 0 | assert (sock != NULL); |
160 | 0 | if (sock->read_fd != -1) |
161 | 0 | close (sock->read_fd); |
162 | 0 | sock->read_fd = -1; |
163 | | #ifdef OS_WIN32 |
164 | | if (sock->write_fd != -1) |
165 | | close (sock->write_fd); |
166 | | sock->write_fd = -1; |
167 | | #endif |
168 | 0 | } |
169 | | |
170 | | static void |
171 | | rpc_socket_unref (rpc_socket *sock) |
172 | 0 | { |
173 | 0 | int release = 0; |
174 | |
|
175 | 0 | assert (sock != NULL); |
176 | | |
177 | 0 | p11_mutex_lock (&sock->write_lock); |
178 | 0 | if (--sock->refs == 0) |
179 | 0 | release = 1; |
180 | 0 | p11_mutex_unlock (&sock->write_lock); |
181 | |
|
182 | 0 | if (!release) |
183 | 0 | return; |
184 | | |
185 | 0 | assert (sock != NULL); |
186 | 0 | assert (sock->refs == 0); |
187 | | |
188 | 0 | rpc_socket_close (sock); |
189 | 0 | p11_mutex_uninit (&sock->write_lock); |
190 | 0 | p11_mutex_uninit (&sock->read_lock); |
191 | 0 | #ifdef OS_UNIX |
192 | 0 | p11_cond_uninit (&sock->read_code_cond); |
193 | 0 | #endif |
194 | 0 | free (sock); |
195 | 0 | } |
196 | | |
197 | | static bool |
198 | | write_all (int fd, |
199 | | unsigned char* data, |
200 | | size_t len) |
201 | 0 | { |
202 | 0 | int r; |
203 | |
|
204 | 0 | while (len > 0) { |
205 | 0 | r = write (fd, data, len); |
206 | 0 | if (r == -1) { |
207 | 0 | if (errno == EPIPE) { |
208 | 0 | p11_message (_("couldn't send data: closed connection")); |
209 | 0 | return false; |
210 | 0 | } else if (errno != EAGAIN && errno != EINTR) { |
211 | 0 | p11_message_err (errno, _("couldn't send data")); |
212 | 0 | return false; |
213 | 0 | } |
214 | 0 | } else { |
215 | 0 | p11_debug ("wrote %d bytes", r); |
216 | 0 | data += r; |
217 | 0 | len -= r; |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | 0 | return true; |
222 | 0 | } |
223 | | |
224 | | static bool |
225 | | read_all (int fd, |
226 | | unsigned char* data, |
227 | | size_t len) |
228 | 0 | { |
229 | 0 | int r; |
230 | |
|
231 | 0 | while (len > 0) { |
232 | 0 | r = read (fd, data, len); |
233 | 0 | if (r == 0) { |
234 | 0 | p11_message (_("couldn't receive data: closed connection")); |
235 | 0 | return false; |
236 | 0 | } else if (r == -1) { |
237 | 0 | if (errno != EAGAIN && errno != EINTR) { |
238 | 0 | p11_message_err (errno, _("couldn't receive data")); |
239 | 0 | return false; |
240 | 0 | } |
241 | 0 | } else { |
242 | 0 | p11_debug ("read %d bytes", r); |
243 | 0 | data += r; |
244 | 0 | len -= r; |
245 | 0 | } |
246 | 0 | } |
247 | | |
248 | 0 | return true; |
249 | 0 | } |
250 | | |
251 | | static CK_RV |
252 | | rpc_socket_write_inlock (rpc_socket *sock, |
253 | | int code, |
254 | | p11_buffer *options, |
255 | | p11_buffer *buffer) |
256 | 0 | { |
257 | 0 | unsigned char header[12]; |
258 | | |
259 | | /* The socket is locked and referenced at this point */ |
260 | 0 | assert (buffer != NULL); |
261 | | |
262 | 0 | p11_rpc_buffer_encode_uint32 (header, code); |
263 | 0 | p11_rpc_buffer_encode_uint32 (header + 4, options->len); |
264 | 0 | p11_rpc_buffer_encode_uint32 (header + 8, buffer->len); |
265 | |
|
266 | 0 | if (!write_all (sock->write_fd, header, 12) || |
267 | 0 | !write_all (sock->write_fd, options->data, options->len) || |
268 | 0 | !write_all (sock->write_fd, buffer->data, buffer->len)) |
269 | 0 | return CKR_DEVICE_ERROR; |
270 | | |
271 | 0 | return CKR_OK; |
272 | 0 | } |
273 | | |
274 | | static p11_rpc_status |
275 | | write_at (int fd, |
276 | | unsigned char *data, |
277 | | size_t len, |
278 | | size_t offset, |
279 | | size_t *at) |
280 | 0 | { |
281 | 0 | p11_rpc_status status; |
282 | 0 | ssize_t num; |
283 | 0 | size_t from; |
284 | 0 | int errn; |
285 | |
|
286 | 0 | assert (*at >= offset); |
287 | | |
288 | 0 | if (*at >= offset + len) |
289 | 0 | return P11_RPC_OK; |
290 | | |
291 | 0 | from = *at - offset; |
292 | 0 | assert (from < len); |
293 | | |
294 | 0 | num = write (fd, data + from, len - from); |
295 | 0 | errn = errno; |
296 | | |
297 | | /* Update state */ |
298 | 0 | if (num > 0) |
299 | 0 | *at += num; |
300 | | |
301 | | /* Completely written out this block */ |
302 | 0 | if (num == len - from) { |
303 | 0 | p11_debug ("ok: wrote block of %d", (int)num); |
304 | 0 | status = P11_RPC_OK; |
305 | | |
306 | | /* Partially written out this block */ |
307 | 0 | } else if (num >= 0) { |
308 | 0 | p11_debug ("again: partial read of %d", (int)num); |
309 | 0 | status = P11_RPC_AGAIN; |
310 | | |
311 | | /* Didn't write out block due to transient issue */ |
312 | 0 | } else if (errn == EINTR || errn == EAGAIN || errn == EWOULDBLOCK) { |
313 | 0 | p11_debug ("again: due to %d", errn); |
314 | 0 | status = P11_RPC_AGAIN; |
315 | | |
316 | | /* Failure */ |
317 | 0 | } else { |
318 | 0 | p11_debug ("error: due to %d", errn); |
319 | 0 | status = P11_RPC_ERROR; |
320 | 0 | } |
321 | |
|
322 | 0 | errno = errn; |
323 | 0 | return status; |
324 | 0 | } |
325 | | |
326 | | p11_rpc_status |
327 | | p11_rpc_transport_write (int fd, |
328 | | size_t *state, |
329 | | int call_code, |
330 | | p11_buffer *options, |
331 | | p11_buffer *buffer) |
332 | 0 | { |
333 | 0 | unsigned char header[12] = { 0, }; |
334 | 0 | p11_rpc_status status; |
335 | |
|
336 | 0 | assert (state != NULL); |
337 | 0 | assert (options != NULL); |
338 | 0 | assert (buffer != NULL); |
339 | | |
340 | 0 | if (*state < 12) { |
341 | 0 | p11_rpc_buffer_encode_uint32 (header, call_code); |
342 | 0 | p11_rpc_buffer_encode_uint32 (header + 4, options->len); |
343 | 0 | p11_rpc_buffer_encode_uint32 (header + 8, buffer->len); |
344 | 0 | } |
345 | |
|
346 | 0 | status = write_at (fd, header, 12, 0, state); |
347 | |
|
348 | 0 | if (status == P11_RPC_OK) { |
349 | 0 | status = write_at (fd, options->data, options->len, |
350 | 0 | 12, state); |
351 | 0 | } |
352 | |
|
353 | 0 | if (status == P11_RPC_OK) { |
354 | 0 | status = write_at (fd, buffer->data, buffer->len, |
355 | 0 | 12 + options->len, state); |
356 | 0 | } |
357 | | |
358 | | /* All done */ |
359 | 0 | if (status == P11_RPC_OK) |
360 | 0 | *state = 0; |
361 | |
|
362 | 0 | return status; |
363 | 0 | } |
364 | | |
365 | | static void |
366 | | rpc_socket_set_read_code_inlock (rpc_socket *sock, |
367 | | int code) |
368 | 0 | { |
369 | 0 | sock->read_code = code; |
370 | 0 | #ifdef OS_UNIX |
371 | 0 | p11_cond_broadcast (&sock->read_code_cond); |
372 | 0 | #endif |
373 | 0 | } |
374 | | |
375 | | #ifdef OS_UNIX |
376 | | static void |
377 | | rpc_socket_wait_for_read_code_change_inlock (rpc_socket *sock) |
378 | 0 | { |
379 | 0 | p11_cond_wait (&sock->read_code_cond, &sock->read_lock); |
380 | 0 | } |
381 | | #endif |
382 | | |
383 | | static int |
384 | | rpc_socket_read (rpc_socket *sock, |
385 | | int *code, |
386 | | p11_buffer *buffer) |
387 | 0 | { |
388 | 0 | CK_RV ret = CKR_DEVICE_ERROR; |
389 | 0 | unsigned char header[12]; |
390 | | #ifdef OS_WIN32 |
391 | | HANDLE handle; |
392 | | DWORD mode; |
393 | | #endif |
394 | |
|
395 | 0 | assert (code != NULL); |
396 | 0 | assert (buffer != NULL); |
397 | | |
398 | | /* |
399 | | * We are not in the main socket lock here, but the socket |
400 | | * is referenced, and won't go away |
401 | | */ |
402 | | |
403 | 0 | p11_mutex_lock (&sock->read_lock); |
404 | |
|
405 | 0 | for (;;) { |
406 | | /* No message header has been read yet? ... read one in */ |
407 | 0 | if (sock->read_code == 0) { |
408 | 0 | if (!read_all (sock->read_fd, header, 12)) |
409 | 0 | break; |
410 | | |
411 | | /* Decode and check the message header */ |
412 | 0 | rpc_socket_set_read_code_inlock (sock, p11_rpc_buffer_decode_uint32 (header)); |
413 | 0 | sock->read_olen = p11_rpc_buffer_decode_uint32 (header + 4); |
414 | 0 | sock->read_dlen = p11_rpc_buffer_decode_uint32 (header + 8); |
415 | 0 | if (sock->read_code == 0) { |
416 | 0 | p11_message (_("received invalid rpc header values: perhaps wrong protocol")); |
417 | 0 | break; |
418 | 0 | } |
419 | 0 | } |
420 | | |
421 | | /* If it's our header (or caller doesn't care), then yay! */ |
422 | 0 | if (*code == -1 || sock->read_code == *code) { |
423 | | |
424 | | /* We ignore the options, so read into the same as buffer */ |
425 | 0 | if (!p11_buffer_reset (buffer, sock->read_olen) || |
426 | 0 | !p11_buffer_reset (buffer, sock->read_dlen)) { |
427 | 0 | warn_if_reached (); |
428 | 0 | break; |
429 | 0 | } |
430 | | |
431 | | /* Read in the the options first, and then data */ |
432 | 0 | if (!read_all (sock->read_fd, buffer->data, sock->read_olen) || |
433 | 0 | !read_all (sock->read_fd, buffer->data, sock->read_dlen)) |
434 | 0 | break; |
435 | | |
436 | 0 | buffer->len = sock->read_dlen; |
437 | 0 | *code = sock->read_code; |
438 | | |
439 | | /* Yay, we got our data, off we go */ |
440 | 0 | rpc_socket_set_read_code_inlock (sock, 0); |
441 | 0 | sock->read_olen = 0; |
442 | 0 | sock->read_dlen = 0; |
443 | 0 | ret = CKR_OK; |
444 | 0 | break; |
445 | 0 | } |
446 | | |
447 | | /* Give another thread the chance to read data for this header */ |
448 | 0 | if (sock->read_code != 0) { |
449 | 0 | p11_debug ("received header in wrong thread"); |
450 | |
|
451 | 0 | #ifdef OS_UNIX |
452 | 0 | rpc_socket_wait_for_read_code_change_inlock (sock); |
453 | 0 | #endif |
454 | | #ifdef OS_WIN32 |
455 | | /* Used as a simple wait */ |
456 | | p11_mutex_unlock (&sock->read_lock); |
457 | | handle = (HANDLE) _get_osfhandle (sock->read_fd); |
458 | | if (!ReadFile (handle, NULL, 0, &mode, NULL)) |
459 | | p11_message (_("couldn't use select to wait on rpc pipe")); |
460 | | p11_mutex_lock (&sock->read_lock); |
461 | | #endif |
462 | 0 | } |
463 | 0 | } |
464 | |
|
465 | 0 | p11_mutex_unlock (&sock->read_lock); |
466 | 0 | return ret; |
467 | 0 | } |
468 | | |
469 | | static p11_rpc_status |
470 | | read_at (int fd, |
471 | | unsigned char *data, |
472 | | size_t len, |
473 | | size_t offset, |
474 | | size_t *at) |
475 | 0 | { |
476 | 0 | p11_rpc_status status; |
477 | 0 | int errn; |
478 | 0 | ssize_t num; |
479 | 0 | size_t from; |
480 | |
|
481 | 0 | assert (*at >= offset); |
482 | | |
483 | 0 | if (*at >= offset + len) |
484 | 0 | return P11_RPC_OK; |
485 | | |
486 | 0 | from = *at - offset; |
487 | 0 | assert (from < len); |
488 | | |
489 | 0 | num = read (fd, data + from, len - from); |
490 | 0 | errn = errno; |
491 | | |
492 | | /* Update state */ |
493 | 0 | if (num > 0) |
494 | 0 | *at += num; |
495 | | |
496 | | /* Completely read out this block */ |
497 | 0 | if (num == len - from) { |
498 | 0 | p11_debug ("ok: read block of %d", (int)num); |
499 | 0 | status = P11_RPC_OK; |
500 | | |
501 | | /* Partially read out this block */ |
502 | 0 | } else if (num > 0) { |
503 | 0 | p11_debug ("again: partial read of %d", (int)num); |
504 | 0 | status = P11_RPC_AGAIN; |
505 | | |
506 | | /* End of file, valid if at offset zero */ |
507 | 0 | } else if (num == 0) { |
508 | 0 | if (offset == 0) { |
509 | 0 | p11_debug ("eof: read zero bytes"); |
510 | 0 | status = P11_RPC_EOF; |
511 | 0 | } else { |
512 | 0 | p11_debug ("error: early truncate"); |
513 | 0 | errn = EPROTO; |
514 | 0 | status = P11_RPC_ERROR; |
515 | 0 | } |
516 | | |
517 | | /* Didn't read out block due to transient issue */ |
518 | 0 | } else if (errn == EINTR || errn == EAGAIN || errn == EWOULDBLOCK) { |
519 | 0 | p11_debug ("again: due to %d", errn); |
520 | 0 | status = P11_RPC_AGAIN; |
521 | | |
522 | | /* Failure */ |
523 | 0 | } else { |
524 | 0 | p11_debug ("error: due to %d", errn); |
525 | 0 | status = P11_RPC_ERROR; |
526 | 0 | } |
527 | |
|
528 | 0 | errno = errn; |
529 | 0 | return status; |
530 | 0 | } |
531 | | |
532 | | p11_rpc_status |
533 | | p11_rpc_transport_read (int fd, |
534 | | size_t *state, |
535 | | int *call_code, |
536 | | p11_buffer *options, |
537 | | p11_buffer *buffer) |
538 | 0 | { |
539 | 0 | unsigned char *header; |
540 | 0 | p11_rpc_status status; |
541 | 0 | size_t len; |
542 | |
|
543 | 0 | assert (state != NULL); |
544 | 0 | assert (call_code != NULL); |
545 | 0 | assert (options != NULL); |
546 | 0 | assert (buffer != NULL); |
547 | | |
548 | | /* Reading the header, we read it into @buffer */ |
549 | 0 | if (*state < 12) { |
550 | 0 | if (!p11_buffer_reset (buffer, 12)) |
551 | 0 | return_val_if_reached (P11_RPC_ERROR); |
552 | 0 | status = read_at (fd, buffer->data, 12, 0, state); |
553 | 0 | if (status != P11_RPC_OK) |
554 | 0 | return status; |
555 | | |
556 | | /* Parse out the header */ |
557 | 0 | header = buffer->data; |
558 | 0 | *call_code = p11_rpc_buffer_decode_uint32 (header); |
559 | 0 | len = p11_rpc_buffer_decode_uint32 (header + 4); |
560 | 0 | if (!p11_buffer_reset (options, len)) |
561 | 0 | return_val_if_reached (P11_RPC_ERROR); |
562 | 0 | options->len = len; |
563 | 0 | len = p11_rpc_buffer_decode_uint32 (header + 8); |
564 | 0 | if (!p11_buffer_reset (buffer, len)) |
565 | 0 | return_val_if_reached (P11_RPC_ERROR); |
566 | 0 | buffer->len = len; |
567 | 0 | } |
568 | | |
569 | | /* At this point options has a valid len field */ |
570 | 0 | status = read_at (fd, options->data, options->len, 12, state); |
571 | 0 | if (status == P11_RPC_OK) { |
572 | 0 | status = read_at (fd, buffer->data, buffer->len, |
573 | 0 | 12 + options->len, state); |
574 | 0 | } |
575 | |
|
576 | 0 | if (status == P11_RPC_OK) |
577 | 0 | *state = 0; |
578 | |
|
579 | 0 | return status; |
580 | 0 | } |
581 | | |
582 | | struct _p11_rpc_transport { |
583 | | p11_rpc_client_vtable vtable; |
584 | | p11_destroyer destroyer; |
585 | | rpc_socket *socket; |
586 | | p11_buffer options; |
587 | | }; |
588 | | |
589 | | static void |
590 | | rpc_transport_disconnect (p11_rpc_client_vtable *vtable, |
591 | | void *init_reserved) |
592 | 0 | { |
593 | 0 | p11_rpc_transport *rpc = (p11_rpc_transport *)vtable; |
594 | |
|
595 | 0 | if (rpc->socket) { |
596 | 0 | rpc_socket_close (rpc->socket); |
597 | 0 | rpc_socket_unref (rpc->socket); |
598 | 0 | rpc->socket = NULL; |
599 | 0 | } |
600 | 0 | } |
601 | | |
602 | | static bool |
603 | | rpc_transport_init (p11_rpc_transport *rpc, |
604 | | const char *module_name, |
605 | | p11_destroyer destroyer) |
606 | 0 | { |
607 | 0 | rpc->destroyer = destroyer; |
608 | |
|
609 | 0 | p11_buffer_init_null (&rpc->options, 0); |
610 | 0 | p11_buffer_add (&rpc->options, module_name, -1); |
611 | 0 | return_val_if_fail (p11_buffer_ok (&rpc->options), false); |
612 | | |
613 | 0 | return true; |
614 | 0 | } |
615 | | |
616 | | static void |
617 | | rpc_transport_uninit (p11_rpc_transport *rpc) |
618 | 0 | { |
619 | 0 | p11_buffer_uninit (&rpc->options); |
620 | 0 | } |
621 | | |
622 | | static CK_RV |
623 | | rpc_transport_authenticate (p11_rpc_client_vtable *vtable, |
624 | | uint8_t *version) |
625 | 0 | { |
626 | 0 | p11_rpc_transport *rpc = (p11_rpc_transport *)vtable; |
627 | 0 | rpc_socket *sock; |
628 | |
|
629 | 0 | assert (rpc != NULL); |
630 | 0 | assert (version != NULL); |
631 | | |
632 | 0 | sock = rpc->socket; |
633 | 0 | assert (sock != NULL); |
634 | | |
635 | 0 | if (sock->read_fd == -1) { |
636 | 0 | return CKR_DEVICE_ERROR; |
637 | 0 | } |
638 | | #ifdef OS_WIN32 |
639 | | if (sock->write_fd == -1) { |
640 | | return CKR_DEVICE_ERROR; |
641 | | } |
642 | | #endif |
643 | | |
644 | 0 | p11_debug ("authenticating with version %u", *version); |
645 | | |
646 | | /* Place holder byte, will later carry unix credentials (on some systems) */ |
647 | 0 | if (write_all (sock->write_fd, version, 1) != 1) { |
648 | 0 | p11_message_err (errno, _("couldn't send socket credentials")); |
649 | 0 | return CKR_DEVICE_ERROR; |
650 | 0 | } |
651 | | |
652 | 0 | if (read_all (sock->read_fd, version, 1) != 1) { |
653 | 0 | p11_message_err (errno, _("couldn't receive socket credentials")); |
654 | 0 | return CKR_DEVICE_ERROR; |
655 | 0 | } |
656 | | |
657 | | #if P11_RPC_PROTOCOL_VERSION_MINIMUM > 0 |
658 | | if (*version < P11_RPC_PROTOCOL_VERSION_MINIMUM) { |
659 | | p11_message_err (errno, _("peer protocol version is too old")); |
660 | | return CKR_DEVICE_ERROR; |
661 | | } |
662 | | #endif |
663 | | |
664 | 0 | return CKR_OK; |
665 | 0 | } |
666 | | |
667 | | static CK_RV |
668 | | rpc_transport_buffer (p11_rpc_client_vtable *vtable, |
669 | | p11_buffer *request, |
670 | | p11_buffer *response) |
671 | 0 | { |
672 | 0 | p11_rpc_transport *rpc = (p11_rpc_transport *)vtable; |
673 | 0 | CK_RV rv = CKR_OK; |
674 | 0 | rpc_socket *sock; |
675 | 0 | int call_code; |
676 | |
|
677 | 0 | assert (rpc != NULL); |
678 | 0 | assert (request != NULL); |
679 | 0 | assert (response != NULL); |
680 | | |
681 | 0 | sock = rpc->socket; |
682 | 0 | assert (sock != NULL); |
683 | | |
684 | 0 | p11_mutex_lock (&sock->write_lock); |
685 | 0 | assert (sock->refs > 0); |
686 | 0 | sock->refs++; |
687 | | |
688 | | /* Get the next socket reply code */ |
689 | 0 | call_code = sock->last_code++; |
690 | |
|
691 | 0 | if (sock->read_fd == -1) |
692 | 0 | rv = CKR_DEVICE_ERROR; |
693 | | #ifdef OS_WIN32 |
694 | | if (sock->write_fd == -1) |
695 | | rv = CKR_DEVICE_ERROR; |
696 | | #endif |
697 | 0 | if (rv == CKR_OK) |
698 | 0 | rv = rpc_socket_write_inlock (sock, call_code, &rpc->options, request); |
699 | | |
700 | | /* We unlock the socket mutex while reading a response */ |
701 | 0 | if (rv == CKR_OK) { |
702 | 0 | p11_mutex_unlock (&sock->write_lock); |
703 | |
|
704 | 0 | rv = rpc_socket_read (sock, &call_code, response); |
705 | |
|
706 | 0 | p11_mutex_lock (&sock->write_lock); |
707 | 0 | } |
708 | |
|
709 | 0 | if (rv != CKR_OK && sock->read_fd != -1) { |
710 | 0 | p11_message (_("closing socket due to protocol failure")); |
711 | 0 | close (sock->read_fd); |
712 | 0 | sock->read_fd = -1; |
713 | 0 | } |
714 | | #ifdef OS_WIN32 |
715 | | if (rv != CKR_OK && sock->write_fd != -1) { |
716 | | p11_message (_("closing socket due to protocol failure")); |
717 | | close (sock->write_fd); |
718 | | sock->write_fd = -1; |
719 | | } |
720 | | #endif |
721 | |
|
722 | 0 | sock->refs--; |
723 | 0 | assert (sock->refs > 0); |
724 | 0 | p11_mutex_unlock (&sock->write_lock); |
725 | |
|
726 | 0 | return rv; |
727 | 0 | } |
728 | | |
729 | | #ifdef OS_UNIX |
730 | | |
731 | | typedef struct { |
732 | | p11_rpc_transport base; |
733 | | p11_array *argv; |
734 | | pid_t pid; |
735 | | } rpc_exec; |
736 | | |
737 | | static void |
738 | | rpc_exec_wait_or_terminate (pid_t pid) |
739 | 0 | { |
740 | 0 | bool terminated = false; |
741 | 0 | int status; |
742 | 0 | int sig; |
743 | 0 | int ret; |
744 | 0 | int i; |
745 | | |
746 | |
|
747 | 0 | for (i = 0; i < 3 * 1000; i += 100) { |
748 | 0 | ret = waitpid (pid, &status, WNOHANG); |
749 | 0 | if (ret != 0) |
750 | 0 | break; |
751 | 0 | p11_sleep_ms (100); |
752 | 0 | } |
753 | |
|
754 | 0 | if (ret == 0) { |
755 | 0 | p11_message (_("process %d did not exit, terminating"), (int)pid); |
756 | 0 | kill (pid, SIGTERM); |
757 | 0 | terminated = true; |
758 | 0 | ret = waitpid (pid, &status, 0); |
759 | 0 | } |
760 | |
|
761 | 0 | if (ret < 0) { |
762 | 0 | p11_message_err (errno, _("failed to wait for executed child: %d"), (int)pid); |
763 | 0 | status = 0; |
764 | 0 | } else if (WIFEXITED (status)) { |
765 | 0 | status = WEXITSTATUS (status); |
766 | 0 | if (status == 0) |
767 | 0 | p11_debug ("process %d exited with status 0", (int)pid); |
768 | 0 | else |
769 | 0 | p11_message (_("process %d exited with status %d"), (int)pid, status); |
770 | 0 | } else if (WIFSIGNALED (status)) { |
771 | 0 | sig = WTERMSIG (status); |
772 | 0 | if (!terminated || sig != SIGTERM) |
773 | 0 | p11_message (_("process %d was terminated with signal %d"), (int)pid, sig); |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | static void |
778 | | rpc_exec_disconnect (p11_rpc_client_vtable *vtable, |
779 | | void *fini_reserved) |
780 | 0 | { |
781 | 0 | rpc_exec *rex = (rpc_exec *)vtable; |
782 | |
|
783 | 0 | if (rex->base.socket) |
784 | 0 | rpc_socket_close (rex->base.socket); |
785 | |
|
786 | 0 | if (rex->pid) |
787 | 0 | rpc_exec_wait_or_terminate (rex->pid); |
788 | 0 | rex->pid = 0; |
789 | | |
790 | | /* Do the common disconnect stuff */ |
791 | 0 | rpc_transport_disconnect (vtable, fini_reserved); |
792 | 0 | } |
793 | | |
794 | | static int |
795 | | set_cloexec_on_fd (void *data, |
796 | | int fd) |
797 | 0 | { |
798 | 0 | int *max_fd = data; |
799 | 0 | if (fd >= *max_fd) |
800 | 0 | fcntl (fd, F_SETFD, FD_CLOEXEC); |
801 | 0 | return 0; |
802 | 0 | } |
803 | | |
804 | | static CK_RV |
805 | | rpc_exec_connect (p11_rpc_client_vtable *vtable, |
806 | | void *init_reserved) |
807 | 0 | { |
808 | 0 | rpc_exec *rex = (rpc_exec *)vtable; |
809 | 0 | pid_t pid; |
810 | 0 | int max_fd; |
811 | 0 | int fds[2]; |
812 | 0 | int errn; |
813 | |
|
814 | 0 | p11_debug ("executing rpc transport: %s", (char *)rex->argv->elem[0]); |
815 | |
|
816 | 0 | if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) { |
817 | 0 | p11_message_err (errno, _("failed to create pipe for remote")); |
818 | 0 | return CKR_DEVICE_ERROR; |
819 | 0 | } |
820 | | |
821 | 0 | pid = fork (); |
822 | 0 | switch (pid) { |
823 | | |
824 | | /* Failure */ |
825 | 0 | case -1: |
826 | 0 | close (fds[0]); |
827 | 0 | close (fds[1]); |
828 | 0 | p11_message_err (errno, _("failed to fork for remote")); |
829 | 0 | return CKR_DEVICE_ERROR; |
830 | | |
831 | | /* Child */ |
832 | 0 | case 0: |
833 | 0 | if (dup2 (fds[1], STDIN_FILENO) < 0 || |
834 | 0 | dup2 (fds[1], STDOUT_FILENO) < 0) { |
835 | 0 | errn = errno; |
836 | 0 | p11_message_err (errn, "couldn't dup file descriptors in remote child"); |
837 | 0 | _exit (errn); |
838 | 0 | } |
839 | | |
840 | | /* Close file descriptors, except for above on exec */ |
841 | 0 | max_fd = STDERR_FILENO + 1; |
842 | 0 | fdwalk (set_cloexec_on_fd, &max_fd); |
843 | 0 | execvp (rex->argv->elem[0], (char **)rex->argv->elem); |
844 | |
|
845 | 0 | errn = errno; |
846 | 0 | p11_message_err (errn, "couldn't execute program for rpc: %s", |
847 | 0 | (char *)rex->argv->elem[0]); |
848 | 0 | _exit (errn); |
849 | | |
850 | | /* The parent */ |
851 | 0 | default: |
852 | 0 | break; |
853 | 0 | } |
854 | | |
855 | 0 | close (fds[1]); |
856 | 0 | rex->pid = pid; |
857 | 0 | rex->base.socket = rpc_socket_new (fds[0]); |
858 | 0 | return_val_if_fail (rex->base.socket != NULL, CKR_GENERAL_ERROR); |
859 | | |
860 | 0 | return CKR_OK; |
861 | 0 | } |
862 | | |
863 | | #endif /* OS_UNIX */ |
864 | | |
865 | | #ifdef OS_WIN32 |
866 | | |
867 | | typedef struct { |
868 | | p11_rpc_transport base; |
869 | | p11_array *argv; |
870 | | HANDLE pid; |
871 | | } rpc_exec; |
872 | | |
873 | | static void |
874 | | rpc_exec_wait_or_terminate (HANDLE pid) |
875 | | { |
876 | | DWORD status; |
877 | | int ret; |
878 | | int i; |
879 | | |
880 | | |
881 | | for (i = 0; i < 3 * 1000; i += 100) { |
882 | | ret = WaitForSingleObject (pid, 10000); |
883 | | if (ret == WAIT_OBJECT_0) |
884 | | break; |
885 | | } |
886 | | |
887 | | if (ret != WAIT_OBJECT_0) { |
888 | | p11_message (_("process %p did not exit, terminating"), pid); |
889 | | if (!TerminateProcess (pid, SIGTERM)) |
890 | | p11_message (_("couldn't terminate process %p"), pid); |
891 | | ret = WaitForSingleObject (pid, 0); |
892 | | } |
893 | | |
894 | | if (ret != WAIT_OBJECT_0) { |
895 | | p11_message (_("failed to wait for executed child: %p"), pid); |
896 | | status = 0; |
897 | | } else if (!GetExitCodeProcess (pid, &status)) { |
898 | | p11_message (_("failed to get the exit status of %p"), pid); |
899 | | } else if (status == 0) { |
900 | | p11_debug ("process %p exited with status 0", pid); |
901 | | } else { |
902 | | p11_message (_("process %p exited with status %lu"), pid, status); |
903 | | } |
904 | | |
905 | | CloseHandle (pid); |
906 | | } |
907 | | |
908 | | static void |
909 | | rpc_exec_disconnect (p11_rpc_client_vtable *vtable, |
910 | | void *fini_reserved) |
911 | | { |
912 | | rpc_exec *rex = (rpc_exec *)vtable; |
913 | | |
914 | | if (rex->base.socket) |
915 | | rpc_socket_close (rex->base.socket); |
916 | | |
917 | | if (rex->pid != INVALID_HANDLE_VALUE) |
918 | | rpc_exec_wait_or_terminate (rex->pid); |
919 | | rex->pid = INVALID_HANDLE_VALUE; |
920 | | |
921 | | /* Do the common disconnect stuff */ |
922 | | rpc_transport_disconnect (vtable, fini_reserved); |
923 | | } |
924 | | |
925 | | static int |
926 | | set_cloexec_on_fd (int fd) |
927 | | { |
928 | | HANDLE handle; |
929 | | |
930 | | handle = (HANDLE) _get_osfhandle (fd); |
931 | | if (!SetHandleInformation (handle, HANDLE_FLAG_INHERIT, 0)) |
932 | | return -1; |
933 | | |
934 | | return 0; |
935 | | } |
936 | | |
937 | | static CK_RV |
938 | | rpc_exec_connect (p11_rpc_client_vtable *vtable, |
939 | | void *init_reserved) |
940 | | { |
941 | | rpc_exec *rex = (rpc_exec *)vtable; |
942 | | intptr_t pid = -1; |
943 | | int pw[2] = { -1, -1 }, pr[2] = { -1, -1 }; |
944 | | int fds[2] = { -1, -1 }; |
945 | | CK_RV rv = CKR_OK; |
946 | | |
947 | | p11_debug ("executing rpc transport: %s", (char *)rex->argv->elem[0]); |
948 | | |
949 | | setvbuf (stdout, NULL, _IONBF, 0 ); |
950 | | |
951 | | if (_pipe (pw, 256, _O_BINARY) == -1 || |
952 | | set_cloexec_on_fd (pw[1]) == -1) { |
953 | | p11_message_err (errno, _("failed to create pipe for remote")); |
954 | | rv = CKR_DEVICE_ERROR; |
955 | | goto out; |
956 | | } |
957 | | |
958 | | if (_pipe (pr, 256, _O_BINARY) == -1 || |
959 | | set_cloexec_on_fd (pr[0]) == -1) { |
960 | | p11_message_err (errno, _("failed to create pipe for remote")); |
961 | | rv = CKR_DEVICE_ERROR; |
962 | | goto out; |
963 | | } |
964 | | |
965 | | /* Save the original stdin and stdout */ |
966 | | fds[0] = dup (STDIN_FILENO); |
967 | | if (fds[0] == -1) { |
968 | | p11_message_err (errno, _("failed to duplicate stdin")); |
969 | | rv = CKR_DEVICE_ERROR; |
970 | | goto out; |
971 | | } |
972 | | |
973 | | fds[1] = dup (STDOUT_FILENO); |
974 | | if (fds[1] == -1) { |
975 | | p11_message_err (errno, _("failed to duplicate stdout")); |
976 | | rv = CKR_DEVICE_ERROR; |
977 | | goto out; |
978 | | } |
979 | | |
980 | | /* Temporarily redirect pipe descriptors to stdin/stdout for child */ |
981 | | if (dup2 (pw[0], STDIN_FILENO) == -1 || |
982 | | dup2 (pr[1], STDOUT_FILENO) == -1) { |
983 | | p11_message_err (errno, _("failed to duplicate child end of pipe")); |
984 | | rv = CKR_DEVICE_ERROR; |
985 | | goto out; |
986 | | } |
987 | | |
988 | | pid = _spawnv (P_NOWAIT, |
989 | | rex->argv->elem[0], |
990 | | (const char * const *)rex->argv->elem); |
991 | | |
992 | | if (pid == -1) { |
993 | | p11_message_err (errno, _("failed to spawn remote")); |
994 | | rv = CKR_DEVICE_ERROR; |
995 | | goto out; |
996 | | } |
997 | | |
998 | | close (pw[0]); |
999 | | pw[0] = -1; |
1000 | | close (pr[1]); |
1001 | | pr[1] = -1; |
1002 | | |
1003 | | /* Restore the original stdin and stdout */ |
1004 | | if (dup2 (fds[0], STDIN_FILENO) == -1 || |
1005 | | dup2 (fds[1], STDOUT_FILENO) == -1) { |
1006 | | p11_message_err (errno, _("failed to restore file descriptors")); |
1007 | | rv = CKR_DEVICE_ERROR; |
1008 | | goto out; |
1009 | | } |
1010 | | |
1011 | | close (fds[0]); |
1012 | | fds[0] = -1; |
1013 | | close (fds[1]); |
1014 | | fds[1] = -1; |
1015 | | |
1016 | | rex->pid = (HANDLE) pid; |
1017 | | rex->base.socket = rpc_socket_new (pr[0]); |
1018 | | return_val_if_fail (rex->base.socket != NULL, CKR_GENERAL_ERROR); |
1019 | | rex->base.socket->write_fd = pw[1]; |
1020 | | |
1021 | | out: |
1022 | | if (rv != CKR_OK) { |
1023 | | if (pid != -1) { |
1024 | | TerminateProcess ((HANDLE) pid, SIGTERM); |
1025 | | CloseHandle ((HANDLE) pid); |
1026 | | } |
1027 | | if (pw[0] != -1) |
1028 | | close (pw[0]); |
1029 | | if (pw[1] != -1) |
1030 | | close (pw[1]); |
1031 | | if (pr[0] != -1) |
1032 | | close (pr[0]); |
1033 | | if (pr[1] != -1) |
1034 | | close (pr[1]); |
1035 | | if (fds[0] != -1) |
1036 | | close (fds[0]); |
1037 | | if (fds[1] != -1) |
1038 | | close (fds[1]); |
1039 | | } |
1040 | | |
1041 | | return rv; |
1042 | | } |
1043 | | |
1044 | | #endif /* OS_WIN32 */ |
1045 | | |
1046 | | static void |
1047 | | rpc_exec_free (void *data) |
1048 | 0 | { |
1049 | 0 | rpc_exec *rex = data; |
1050 | 0 | rpc_exec_disconnect (data, NULL); |
1051 | 0 | rpc_transport_uninit (&rex->base); |
1052 | 0 | p11_array_free (rex->argv); |
1053 | 0 | free (rex); |
1054 | 0 | } |
1055 | | |
1056 | | static void |
1057 | | on_argv_parsed (char *argument, |
1058 | | void *data) |
1059 | 0 | { |
1060 | 0 | p11_array *argv = data; |
1061 | |
|
1062 | 0 | if (!p11_array_push (argv, strdup (argument))) |
1063 | 0 | return_if_reached (); |
1064 | 0 | } |
1065 | | |
1066 | | static p11_rpc_transport * |
1067 | | rpc_exec_init (const char *remote, |
1068 | | const char *name) |
1069 | 0 | { |
1070 | 0 | p11_array *argv; |
1071 | 0 | rpc_exec *rex; |
1072 | |
|
1073 | 0 | argv = p11_array_new (free); |
1074 | 0 | if (!p11_argv_parse (remote, on_argv_parsed, argv) || argv->num < 1) { |
1075 | 0 | p11_message (_("invalid remote command line: %s"), remote); |
1076 | 0 | p11_array_free (argv); |
1077 | 0 | return NULL; |
1078 | 0 | } |
1079 | | |
1080 | 0 | rex = calloc (1, sizeof (rpc_exec)); |
1081 | 0 | return_val_if_fail (rex != NULL, NULL); |
1082 | | |
1083 | 0 | p11_array_push (argv, NULL); |
1084 | 0 | rex->argv = argv; |
1085 | | #ifdef OS_WIN32 |
1086 | | rex->pid = INVALID_HANDLE_VALUE; |
1087 | | #endif |
1088 | |
|
1089 | 0 | rex->base.vtable.connect = rpc_exec_connect; |
1090 | 0 | rex->base.vtable.disconnect = rpc_exec_disconnect; |
1091 | 0 | rex->base.vtable.authenticate = rpc_transport_authenticate; |
1092 | 0 | rex->base.vtable.transport = rpc_transport_buffer; |
1093 | 0 | rpc_transport_init (&rex->base, name, rpc_exec_free); |
1094 | |
|
1095 | 0 | p11_debug ("initialized rpc exec: %s", remote); |
1096 | 0 | return &rex->base; |
1097 | 0 | } |
1098 | | |
1099 | | #ifdef OS_UNIX |
1100 | | |
1101 | | typedef struct { |
1102 | | p11_rpc_transport base; |
1103 | | struct sockaddr_un sa; |
1104 | | } rpc_unix; |
1105 | | |
1106 | | static CK_RV |
1107 | | rpc_unix_connect (p11_rpc_client_vtable *vtable, |
1108 | | void *init_reserved) |
1109 | 0 | { |
1110 | 0 | rpc_unix *run = (rpc_unix *)vtable; |
1111 | 0 | int fd; |
1112 | |
|
1113 | 0 | fd = socket (AF_UNIX, SOCK_STREAM, 0); |
1114 | 0 | if (fd < 0) { |
1115 | 0 | p11_message_err (errno, _("failed to create socket for remote")); |
1116 | 0 | return CKR_GENERAL_ERROR; |
1117 | 0 | } |
1118 | | |
1119 | 0 | if (connect (fd, (struct sockaddr *)&run->sa, sizeof (run->sa)) < 0) { |
1120 | 0 | p11_debug_err (errno, "failed to connect to socket"); |
1121 | 0 | close (fd); |
1122 | 0 | return CKR_DEVICE_REMOVED; |
1123 | 0 | } |
1124 | | |
1125 | 0 | run->base.socket = rpc_socket_new (fd); |
1126 | 0 | return_val_if_fail (run->base.socket != NULL, CKR_GENERAL_ERROR); |
1127 | | |
1128 | 0 | return CKR_OK; |
1129 | 0 | } |
1130 | | |
1131 | | static void |
1132 | | rpc_unix_disconnect (p11_rpc_client_vtable *vtable, |
1133 | | void *fini_reserved) |
1134 | 0 | { |
1135 | 0 | rpc_unix *run = (rpc_unix *)vtable; |
1136 | |
|
1137 | 0 | if (run->base.socket) |
1138 | 0 | rpc_socket_close (run->base.socket); |
1139 | | |
1140 | | /* Do the common disconnect stuff */ |
1141 | 0 | rpc_transport_disconnect (vtable, fini_reserved); |
1142 | 0 | } |
1143 | | |
1144 | | static void |
1145 | | rpc_unix_free (void *data) |
1146 | 0 | { |
1147 | 0 | rpc_unix *run = data; |
1148 | 0 | rpc_unix_disconnect (data, NULL); |
1149 | 0 | rpc_transport_uninit (&run->base); |
1150 | 0 | free (run); |
1151 | 0 | } |
1152 | | |
1153 | | static p11_rpc_transport * |
1154 | | rpc_unix_init (const char *remote, |
1155 | | const char *name) |
1156 | 0 | { |
1157 | 0 | rpc_unix *run; |
1158 | |
|
1159 | 0 | run = calloc (1, sizeof (rpc_unix)); |
1160 | 0 | return_val_if_fail (run != NULL, NULL); |
1161 | | |
1162 | 0 | memset (&run->sa, 0, sizeof (run->sa)); |
1163 | 0 | run->sa.sun_family = AF_UNIX; |
1164 | 0 | snprintf (run->sa.sun_path, sizeof (run->sa.sun_path), "%s", remote); |
1165 | |
|
1166 | 0 | run->base.vtable.connect = rpc_unix_connect; |
1167 | 0 | run->base.vtable.disconnect = rpc_unix_disconnect; |
1168 | 0 | run->base.vtable.authenticate = rpc_transport_authenticate; |
1169 | 0 | run->base.vtable.transport = rpc_transport_buffer; |
1170 | 0 | rpc_transport_init (&run->base, name, rpc_unix_free); |
1171 | |
|
1172 | 0 | p11_debug ("initialized rpc socket: %s", remote); |
1173 | 0 | return &run->base; |
1174 | 0 | } |
1175 | | |
1176 | | #endif /* OS_UNIX */ |
1177 | | |
1178 | | #ifdef HAVE_VSOCK |
1179 | | #include <linux/vm_sockets.h> |
1180 | | #include <vsock.h> |
1181 | | |
1182 | | typedef struct { |
1183 | | p11_rpc_transport base; |
1184 | | struct sockaddr_vm sa; |
1185 | | } rpc_vsock; |
1186 | | |
1187 | | static CK_RV |
1188 | | rpc_vsock_connect (p11_rpc_client_vtable *vtable, |
1189 | | void *init_reserved) |
1190 | 0 | { |
1191 | 0 | rpc_vsock *run = (rpc_vsock *)vtable; |
1192 | 0 | int fd; |
1193 | |
|
1194 | 0 | fd = socket (AF_VSOCK, SOCK_STREAM, 0); |
1195 | 0 | if (fd < 0) { |
1196 | 0 | p11_message_err (errno, _("failed to create socket for remote")); |
1197 | 0 | return CKR_GENERAL_ERROR; |
1198 | 0 | } |
1199 | | |
1200 | 0 | if (connect (fd, (struct sockaddr *)&run->sa, sizeof (run->sa)) < 0) { |
1201 | 0 | p11_debug_err (errno, "failed to connect to socket"); |
1202 | 0 | close (fd); |
1203 | 0 | return CKR_DEVICE_REMOVED; |
1204 | 0 | } |
1205 | | |
1206 | 0 | run->base.socket = rpc_socket_new (fd); |
1207 | 0 | return_val_if_fail (run->base.socket != NULL, CKR_GENERAL_ERROR); |
1208 | | |
1209 | 0 | return CKR_OK; |
1210 | 0 | } |
1211 | | |
1212 | | static void |
1213 | | rpc_vsock_disconnect (p11_rpc_client_vtable *vtable, |
1214 | | void *fini_reserved) |
1215 | 0 | { |
1216 | 0 | rpc_vsock *run = (rpc_vsock *)vtable; |
1217 | |
|
1218 | 0 | if (run->base.socket) |
1219 | 0 | rpc_socket_close (run->base.socket); |
1220 | | |
1221 | | /* Do the common disconnect stuff */ |
1222 | 0 | rpc_transport_disconnect (vtable, fini_reserved); |
1223 | 0 | } |
1224 | | |
1225 | | static void |
1226 | | rpc_vsock_free (void *data) |
1227 | 0 | { |
1228 | 0 | rpc_vsock *run = data; |
1229 | 0 | rpc_vsock_disconnect (data, NULL); |
1230 | 0 | rpc_transport_uninit (&run->base); |
1231 | 0 | free (run); |
1232 | 0 | } |
1233 | | |
1234 | | static p11_rpc_transport * |
1235 | | rpc_vsock_init (unsigned int cid, |
1236 | | unsigned int port, |
1237 | | const char *name) |
1238 | 0 | { |
1239 | 0 | rpc_vsock *run; |
1240 | |
|
1241 | 0 | run = calloc (1, sizeof (rpc_vsock)); |
1242 | 0 | return_val_if_fail (run != NULL, NULL); |
1243 | | |
1244 | 0 | memset (&run->sa, 0, sizeof (run->sa)); |
1245 | 0 | run->sa.svm_family = AF_VSOCK; |
1246 | 0 | run->sa.svm_cid = cid; |
1247 | 0 | run->sa.svm_port = port; |
1248 | |
|
1249 | 0 | run->base.vtable.connect = rpc_vsock_connect; |
1250 | 0 | run->base.vtable.disconnect = rpc_vsock_disconnect; |
1251 | 0 | run->base.vtable.authenticate = rpc_transport_authenticate; |
1252 | 0 | run->base.vtable.transport = rpc_transport_buffer; |
1253 | 0 | rpc_transport_init (&run->base, name, rpc_vsock_free); |
1254 | |
|
1255 | 0 | p11_debug ("initialized rpc socket: vsock:cid=%u;port=%u", |
1256 | 0 | cid, port); |
1257 | 0 | return &run->base; |
1258 | 0 | } |
1259 | | |
1260 | | #endif /* HAVE_VSOCK */ |
1261 | | |
1262 | | p11_rpc_transport * |
1263 | | p11_rpc_transport_new (p11_virtual *virt, |
1264 | | const char *remote, |
1265 | | const char *name) |
1266 | 0 | { |
1267 | 0 | p11_rpc_transport *rpc = NULL; |
1268 | |
|
1269 | 0 | return_val_if_fail (virt != NULL, NULL); |
1270 | 0 | return_val_if_fail (remote != NULL, NULL); |
1271 | 0 | return_val_if_fail (name != NULL, NULL); |
1272 | | |
1273 | | /* This is a command we can execute */ |
1274 | 0 | if (remote[0] == '|') { |
1275 | 0 | rpc = rpc_exec_init (remote + 1, name); |
1276 | |
|
1277 | 0 | #ifdef OS_UNIX |
1278 | 0 | } else if (strncmp (remote, "unix:path=/", 11) == 0) { |
1279 | | /* Only absolute path is supported */ |
1280 | 0 | char *path; |
1281 | |
|
1282 | 0 | path = p11_path_decode (remote + 10); |
1283 | 0 | return_val_if_fail (path != NULL, NULL); |
1284 | 0 | rpc = rpc_unix_init (path, name); |
1285 | 0 | free (path); |
1286 | 0 | #endif /* OS_UNIX */ |
1287 | 0 | #ifdef HAVE_VSOCK |
1288 | 0 | } else if (strncmp (remote, "vsock:", 6) == 0) { |
1289 | 0 | unsigned int cid = 0, port = 0; |
1290 | |
|
1291 | 0 | if (!p11_vsock_parse_addr (remote + 6, &cid, &port) || |
1292 | 0 | cid == VMADDR_CID_ANY) { |
1293 | 0 | p11_message (_("failed to parse vsock address: '%s'"), |
1294 | 0 | remote + 6); |
1295 | 0 | return NULL; |
1296 | 0 | } |
1297 | | |
1298 | 0 | rpc = rpc_vsock_init (cid, port, name); |
1299 | 0 | #endif /* HAVE_VSOCK */ |
1300 | 0 | } else { |
1301 | 0 | p11_message (_("remote not supported: %s"), remote); |
1302 | 0 | return NULL; |
1303 | 0 | } |
1304 | | |
1305 | 0 | return_val_if_fail (rpc != NULL, NULL); |
1306 | | |
1307 | 0 | if (!p11_rpc_client_init (virt, &rpc->vtable)) |
1308 | 0 | return_val_if_reached (NULL); |
1309 | | |
1310 | 0 | return rpc; |
1311 | 0 | } |
1312 | | |
1313 | | void |
1314 | | p11_rpc_transport_free (void *data) |
1315 | 0 | { |
1316 | 0 | p11_rpc_transport *rpc = data; |
1317 | |
|
1318 | 0 | if (rpc != NULL) { |
1319 | 0 | assert (rpc->destroyer); |
1320 | 0 | (rpc->destroyer) (data); |
1321 | 0 | } |
1322 | 0 | } |