git ssb

8+

cel / sbotc



Tree: cec6448afd2f0c42739c510e602283f56518510c

Files: cec6448afd2f0c42739c510e602283f56518510c / sbotc.c

42827 bytesRaw
1/*
2 * sbotc.c
3 * Copyright (c) 2017 Secure Scuttlebutt Consortium
4 *
5 * Usage of the works is permitted provided that this instrument is
6 * retained with the works, so that any entity that uses the works is
7 * notified of this instrument.
8 *
9 * DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
10 */
11
12#include <ctype.h>
13#include <err.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <ifaddrs.h>
17#include <limits.h>
18#include <netdb.h>
19#include <netinet/in.h>
20#include <signal.h>
21#include <stdarg.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/select.h>
27#include <sys/socket.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <sys/un.h>
31#include <termios.h>
32#include <unistd.h>
33
34#include <sodium.h>
35
36#include "jsmn.h"
37
38#define BOXS_MAXLEN 4096
39
40#define write_buf(fd, buf) \
41 write_all(fd, buf, sizeof(buf)-1)
42
43struct boxs_header {
44 uint16_t len;
45 uint8_t mac[16];
46};
47
48struct boxs {
49 int s;
50 unsigned char encrypt_key[32];
51 unsigned char decrypt_key[32];
52 unsigned char nonce1[24];
53 unsigned char nonce2[24];
54 unsigned char rx_nonce[24];
55 unsigned char rx_buf[BOXS_MAXLEN];
56 size_t rx_buf_pos;
57 size_t rx_buf_len;
58 bool noauth;
59 bool wrote_goodbye;
60};
61
62enum pkt_type {
63 pkt_type_buffer = 0,
64 pkt_type_string = 1,
65 pkt_type_json = 2,
66};
67
68enum pkt_flags {
69 pkt_flags_buffer = 0,
70 pkt_flags_string = 1,
71 pkt_flags_json = 2,
72 pkt_flags_end = 4,
73 pkt_flags_stream = 8,
74};
75
76enum muxrpc_type {
77 muxrpc_type_async,
78 muxrpc_type_source,
79 muxrpc_type_sink,
80 muxrpc_type_duplex,
81};
82
83enum stream_state {
84 stream_state_open,
85 stream_state_ended_ok,
86 stream_state_ended_error,
87};
88
89enum ip_family {
90 ip_family_ipv4 = AF_INET,
91 ip_family_ipv6 = AF_INET6,
92 ip_family_any = AF_UNSPEC
93};
94
95static unsigned char zeros[24] = {0};
96
97static const unsigned char ssb_cap[] = {
98 0xd4, 0xa1, 0xcb, 0x88, 0xa6, 0x6f, 0x02, 0xf8,
99 0xdb, 0x63, 0x5c, 0xe2, 0x64, 0x41, 0xcc, 0x5d,
100 0xac, 0x1b, 0x08, 0x42, 0x0c, 0xea, 0xac, 0x23,
101 0x08, 0x39, 0xb7, 0x55, 0x84, 0x5a, 0x9f, 0xfb
102};
103
104struct termios orig_tc;
105
106static void reset_termios() {
107 int rc = tcsetattr(STDIN_FILENO, TCSANOW, &orig_tc);
108 if (rc < 0) warn("tcsetattr");
109}
110
111static void usage() {
112 fputs("usage: sbotc [-j] [-T] [-l] [-r] [-e]\n"
113 " [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]\n"
114 " [ [-s <host>] [-p <port>] [ -4 | -6 ] [-d] | [-u <socket_path>] ]\n"
115 " [ -a | [-t <type>] <method> [<argument>...] ]\n", stderr);
116 exit(EXIT_FAILURE);
117}
118
119static int connect_localhost(const char *port, enum ip_family ip_family) {
120 int rc, family, fd, err;
121 struct ifaddrs *ifaddr, *ifa;
122 rc = getifaddrs(&ifaddr);
123 if (rc < 0) return -1;
124 int port_n = htons(atoi(port));
125
126 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
127 if (ifa->ifa_addr == NULL) continue;
128 family = ifa->ifa_addr->sa_family;
129 socklen_t addrlen;
130 if (family == AF_INET) {
131 if (ip_family != ip_family_ipv4 && ip_family != ip_family_any) continue;
132 addrlen = sizeof(struct sockaddr_in);
133 struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr;
134 addr->sin_port = port_n;
135 } else if (family == AF_INET6) {
136 if (ip_family != ip_family_ipv6 && ip_family != ip_family_any) continue;
137 addrlen = sizeof(struct sockaddr_in6);
138 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ifa->ifa_addr;
139 addr->sin6_port = port_n;
140 } else continue;
141 fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
142 if (fd < 0) continue;
143 if (connect(fd, ifa->ifa_addr, addrlen) == 0) break;
144 err = errno;
145 close(fd);
146 errno = err;
147 }
148 if (ifa == NULL) fd = -1;
149
150 freeifaddrs(ifaddr);
151 return fd;
152}
153
154static int tcp_connect(const char *host, const char *port, enum ip_family ip_family, bool server) {
155 struct addrinfo hints;
156 struct addrinfo *result, *rp;
157 int s;
158 int fd;
159 int err, rc;
160
161 memset(&hints, 0, sizeof(hints));
162 hints.ai_family = ip_family;
163 hints.ai_protocol = IPPROTO_TCP;
164 if (server) hints.ai_flags = AI_PASSIVE;
165
166 s = getaddrinfo(host, port, &hints, &result);
167 if (s < 0) errx(1, "unable to resolve host: %s", gai_strerror(s));
168
169 for (rp = result; rp; rp = rp->ai_next) {
170 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
171 if (fd < 0) continue;
172 if (server) {
173 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
174 if (rc < 0) goto error;
175 if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0) goto error;
176 if (listen(fd, 1) == 0) break;
177 } else {
178 if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) break;
179 }
180error:
181 err = errno;
182 close(fd);
183 errno = err;
184 }
185 if (rp == NULL) fd = -1;
186
187 freeaddrinfo(result);
188
189 if (!server && fd == -1 && errno == ECONNREFUSED && (host == NULL || !strcmp(host, "localhost"))) {
190 return connect_localhost(port, ip_family);
191 }
192
193 if (server && fd > -1) {
194 int client = accept(fd, NULL, NULL);
195 err = errno;
196 close(fd);
197 errno = err;
198 return client;
199 }
200
201 return fd;
202}
203
204static const char *socket_path = NULL;
205
206void cleanup() {
207 if (socket_path != NULL) {
208 int rc = unlink(socket_path);
209 if (rc < 0) warn("unlink");
210 }
211}
212
213static int unix_connect(const char *path, bool server) {
214 struct sockaddr_un name;
215 const size_t path_len = strlen(path);
216 int s, rc;
217 if (path_len >= sizeof(name.sun_path)-1) errx(1, "socket path too long");
218 s = socket(AF_UNIX, SOCK_STREAM, 0);
219 if (s < 0) return -1;
220 memset(&name, 0, sizeof(struct sockaddr_un));
221 name.sun_family = AF_UNIX;
222 strncpy(name.sun_path, path, sizeof(name.sun_path) - 1);
223 if (server) {
224 rc = bind(s, (const struct sockaddr *)&name, sizeof name);
225 if (rc < 0) return -1;
226 rc = listen(s, 1);
227 } else {
228 rc = connect(s, (const struct sockaddr *)&name, sizeof name);
229 }
230 if (rc < 0) return -1;
231
232 if (server && rc > -1) {
233 socket_path = strdup(path);
234 if (atexit(cleanup) < 0) warn("atexit");
235 if (signal(SIGINT, exit) == SIG_ERR) warn("signal");
236 int client = accept(s, NULL, NULL);
237 int err = errno;
238 close(s);
239 errno = err;
240 return client;
241 }
242
243 return s;
244}
245
246static int get_socket_path(char *buf, size_t len, const char *app_dir, bool server) {
247 struct stat st;
248 int sz = snprintf(buf, len-1, "%s/%s", app_dir, "socket");
249 if (sz < 0 || sz >= (int)len-1) err(1, "failed to get socket path");
250 int rc = stat(buf, &st);
251 if (!server) {
252 if (rc < 0) return -1;
253 if (!(st.st_mode & S_IFSOCK)) { errno = EINVAL; return -1; }
254 }
255 return 0;
256}
257
258static int read_all(int fd, void *buf, size_t count) {
259 ssize_t nbytes;
260 while (count > 0) {
261 nbytes = read(fd, buf, count);
262 if (nbytes == 0) { errno = EPIPE; return -1; }
263 if (nbytes < 0 && errno == EINTR) continue;
264 if (nbytes < 0) return -1;
265 buf += nbytes;
266 count -= nbytes;
267 }
268 return 0;
269}
270
271static int read_some(int fd, unsigned char *buf, size_t *lenp) {
272 ssize_t nbytes;
273 do nbytes = read(fd, buf, *lenp);
274 while (nbytes < 0 && errno == EINTR);
275 if (nbytes == 0) { errno = EPIPE; return -1; }
276 if (nbytes < 0) return -1;
277 *lenp = nbytes;
278 return 0;
279}
280
281static int write_all(int fd, const void *buf, size_t count) {
282 ssize_t nbytes;
283 while (count > 0) {
284 nbytes = write(fd, buf, count);
285 if (nbytes < 0 && errno == EINTR) continue;
286 if (nbytes < 0) return -1;
287 buf += nbytes;
288 count -= nbytes;
289 }
290 return 0;
291}
292
293static void shs_connect(int sfd, int infd, int outfd, const unsigned char pubkey[32], const unsigned char seckey[64], const unsigned char appkey[32], const unsigned char remote_pubkey[32], struct boxs *bs, bool client, bool specify_client_key) {
294 int rc;
295 unsigned char client_pubkey[32];
296 unsigned char local_app_mac[32], remote_app_mac[32];
297 unsigned char kx_pk[32], kx_sk[32], remote_kx_pk[32];
298 unsigned char buf[64];
299
300 if (client) {
301 rc = crypto_box_keypair(kx_pk, kx_sk);
302 if (rc < 0) errx(1, "failed to generate auth keypair");
303
304 rc = crypto_auth(local_app_mac, kx_pk, 32, appkey);
305 if (rc < 0) err(1, "failed to generate app mac");
306
307 // send challenge
308 memcpy(buf, local_app_mac, 32);
309 memcpy(buf+32, kx_pk, 32);
310 rc = write_all(outfd, buf, sizeof(buf));
311 if (rc < 0) err(1, "failed to send challenge");
312
313 } else {
314 // recv challenge
315 rc = read_all(infd, buf, sizeof(buf));
316 if (rc < 0) err(1, "expected challenge");
317 memcpy(remote_app_mac, buf, 32);
318 memcpy(remote_kx_pk, buf+32, 32);
319
320 rc = crypto_auth_verify(buf, remote_kx_pk, 32, appkey);
321 if (rc < 0) errx(1, "wrong protocol/version");
322
323 }
324
325 if (client) {
326 // recv challenge
327 rc = read_all(infd, buf, sizeof(buf));
328 if (rc < 0) err(1, "challenge not accepted");
329 memcpy(remote_app_mac, buf, 32);
330 memcpy(remote_kx_pk, buf+32, 32);
331 rc = crypto_auth_verify(buf, remote_kx_pk, 32, appkey);
332 if (rc < 0) errx(1, "wrong protocol (version?)");
333
334 } else {
335 rc = crypto_box_keypair(kx_pk, kx_sk);
336 if (rc < 0) errx(1, "failed to generate auth keypair");
337
338 rc = crypto_auth(local_app_mac, kx_pk, 32, appkey);
339 if (rc < 0) err(1, "failed to generate app mac");
340
341 // send challenge
342 memcpy(buf, local_app_mac, 32);
343 memcpy(buf+32, kx_pk, 32);
344 rc = write_all(outfd, buf, sizeof(buf));
345 if (rc < 0) err(1, "failed to send challenge");
346
347 }
348
349 unsigned char remote_pk_curve[32];
350 unsigned char hello[96];
351 unsigned char secret2[32];
352 unsigned char boxed_auth[112];
353 unsigned char secret[32];
354 unsigned char a_bob[32];
355 unsigned char secret2a[96];
356 unsigned char shash[32];
357 unsigned char sig[64];
358 unsigned char signed1[96];
359 unsigned char local_sk_curve[32];
360 if (client) {
361 // send auth
362
363 rc = crypto_scalarmult(secret, kx_sk, remote_kx_pk);
364 if (rc < 0) errx(1, "failed to derive shared secret");
365
366 rc = crypto_sign_ed25519_pk_to_curve25519(remote_pk_curve, remote_pubkey);
367 if (rc < 0) errx(1, "failed to curvify remote public key");
368
369 rc = crypto_scalarmult(a_bob, kx_sk, remote_pk_curve);
370 if (rc < 0) errx(1, "failed to derive a_bob");
371
372 memcpy(secret2a, appkey, 32);
373 memcpy(secret2a+32, secret, 32);
374 memcpy(secret2a+64, a_bob, 32);
375
376 rc = crypto_hash_sha256(secret2, secret2a, sizeof(secret2a));
377 if (rc < 0) errx(1, "failed to hash secret2");
378
379 rc = crypto_hash_sha256(shash, secret, sizeof(secret));
380 if (rc < 0) errx(1, "failed to hash secret");
381
382 unsigned char signed1[96];
383 memcpy(signed1, appkey, 32);
384 memcpy(signed1+32, remote_pubkey, 32);
385 memcpy(signed1+64, shash, 32);
386
387 rc = crypto_sign_detached(sig, NULL, signed1, sizeof(signed1), seckey);
388 if (rc < 0) errx(1, "failed to sign inner hello");
389
390 memcpy(hello, sig, 64);
391 memcpy(hello+64, pubkey, 32);
392
393 rc = crypto_secretbox_easy(boxed_auth, hello, sizeof(hello), zeros, secret2);
394 if (rc < 0) errx(1, "failed to box hello");
395
396 rc = write_all(outfd, boxed_auth, sizeof(boxed_auth));
397 if (rc < 0) errx(1, "failed to send auth");
398
399 } else {
400 // read auth
401 rc = read_all(infd, boxed_auth, sizeof(boxed_auth));
402 if (rc < 0) err(1, "expected hello");
403
404 rc = crypto_scalarmult(secret, kx_sk, remote_kx_pk);
405 if (rc < 0) errx(1, "failed to derive shared secret");
406
407 rc = crypto_hash_sha256(shash, secret, sizeof(secret));
408 if (rc < 0) errx(1, "failed to hash secret");
409
410 rc = crypto_sign_ed25519_sk_to_curve25519(local_sk_curve, seckey);
411 if (rc < 0) errx(1, "failed to curvify local secret key");
412
413 rc = crypto_scalarmult(a_bob, local_sk_curve, remote_kx_pk);
414 if (rc < 0) errx(1, "failed to derive a_bob");
415
416 memcpy(secret2a, appkey, 32);
417 memcpy(secret2a+32, secret, 32);
418 memcpy(secret2a+64, a_bob, 32);
419
420 rc = crypto_hash_sha256(secret2, secret2a, sizeof(secret2a));
421 if (rc < 0) errx(1, "failed to hash secret2");
422
423 rc = crypto_secretbox_open_easy(hello, boxed_auth, sizeof(boxed_auth), zeros, secret2);
424 if (rc < 0) errx(1, "failed to unbox client hello");
425
426 memcpy(sig, hello, 64);
427 memcpy(client_pubkey, hello+64, 32);
428
429 memcpy(signed1, appkey, 32);
430 memcpy(signed1+32, pubkey, 32);
431 memcpy(signed1+64, shash, 32);
432
433 rc = crypto_sign_verify_detached(sig, signed1, sizeof(signed1), client_pubkey);
434 if (rc < 0) errx(1, "wrong number");
435 }
436
437 unsigned char boxed_okay[80];
438 unsigned char b_alice[32];
439 unsigned char secret3a[128];
440 unsigned char secret3[32];
441 unsigned char signed2[160];
442 if (client) {
443 // verify accept
444
445 rc = read_all(infd, boxed_okay, sizeof(boxed_okay));
446 if (rc < 0) err(1, "hello not accepted");
447
448 rc = crypto_sign_ed25519_sk_to_curve25519(local_sk_curve, seckey);
449 if (rc < 0) errx(1, "failed to curvify local secret key");
450
451 rc = crypto_scalarmult(b_alice, local_sk_curve, remote_kx_pk);
452 if (rc < 0) errx(1, "failed to derive b_alice");
453
454 memcpy(secret3a, appkey, 32);
455 memcpy(secret3a+32, secret, 32);
456 memcpy(secret3a+64, a_bob, 32);
457 memcpy(secret3a+96, b_alice, 32);
458
459 rc = crypto_hash_sha256(secret3, secret3a, sizeof(secret3a));
460 if (rc < 0) errx(1, "failed to hash secret3");
461
462 rc = crypto_secretbox_open_easy(sig, boxed_okay, sizeof(boxed_okay), zeros, secret3);
463 if (rc < 0) errx(1, "failed to unbox the okay");
464
465 memcpy(signed2, appkey, 32);
466 memcpy(signed2+32, hello, 96);
467 memcpy(signed2+128, shash, 32);
468
469 rc = crypto_sign_verify_detached(sig, signed2, sizeof(signed2), remote_pubkey);
470 if (rc < 0) errx(1, "server not authenticated");
471
472 } else {
473 if (specify_client_key && memcmp(client_pubkey, remote_pubkey, 32)) {
474 errx(1, "unexpected client");
475 }
476
477 // send accept
478
479 rc = crypto_sign_ed25519_pk_to_curve25519(remote_pk_curve, client_pubkey);
480 if (rc < 0) errx(1, "failed to curvify remote public key");
481
482 rc = crypto_scalarmult(b_alice, kx_sk, remote_pk_curve);
483 if (rc < 0) errx(1, "failed to derive b_alice");
484
485 memcpy(secret3a, appkey, 32);
486 memcpy(secret3a+32, secret, 32);
487 memcpy(secret3a+64, a_bob, 32);
488 memcpy(secret3a+96, b_alice, 32);
489
490 rc = crypto_hash_sha256(secret3, secret3a, sizeof(secret3a));
491 if (rc < 0) errx(1, "failed to hash secret3");
492
493 memcpy(signed2, appkey, 32);
494 memcpy(signed2+32, hello, 96);
495 memcpy(signed2+128, shash, 32);
496
497 rc = crypto_sign_detached(sig, NULL, signed2, sizeof(signed2), seckey);
498 if (rc < 0) errx(1, "failed to sign inner accept");
499
500 rc = crypto_secretbox_easy(boxed_okay, sig, sizeof(sig), zeros, secret3);
501 if (rc < 0) errx(1, "failed to box accept");
502
503 rc = write_all(outfd, boxed_okay, sizeof(boxed_okay));
504 if (rc < 0) errx(1, "failed to send accept");
505 }
506
507 rc = crypto_hash_sha256(secret, secret3, 32);
508 if (rc < 0) errx(1, "failed to hash secret3");
509
510 unsigned char enc_key_hashed[64];
511 memcpy(enc_key_hashed, secret, 32);
512 memcpy(enc_key_hashed+32, client ? remote_pubkey : client_pubkey, 32);
513 rc = crypto_hash_sha256(bs->encrypt_key, enc_key_hashed, 64);
514 if (rc < 0) errx(1, "failed to hash the encrypt key");
515
516 unsigned char dec_key_hashed[64];
517 memcpy(dec_key_hashed, secret, 32);
518 memcpy(dec_key_hashed+32, pubkey, 32);
519 rc = crypto_hash_sha256(bs->decrypt_key, dec_key_hashed, 64);
520 if (rc < 0) errx(1, "failed to hash the decrypt key");
521
522 memcpy(bs->nonce1, remote_app_mac, 24);
523 memcpy(bs->nonce2, remote_app_mac, 24);
524 memcpy(bs->rx_nonce, local_app_mac, 24);
525
526 bs->rx_buf_pos = 0;
527 bs->rx_buf_len = 0;
528 bs->s = sfd;
529 bs->noauth = false;
530 bs->wrote_goodbye = false;
531}
532
533static int pubkey_decode(const char *key_str, unsigned char key[32]) {
534 if (!key_str) { errno = EPROTO; return -1; }
535 if (!*key_str) { errno = EPROTO; return -1; }
536 if (*key_str == '@') key_str++;
537 size_t len = strlen(key_str);
538 if (len == 52 && strcmp(key_str+44, ".ed25519") == 0) {}
539 else if (len != 44) { errno = EMSGSIZE; return -1; }
540 return sodium_base642bin(
541 (unsigned char *const)key, 32,
542 (const char *const)key_str, 44,
543 NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
544}
545
546static int seckey_decode(const char *key_str, unsigned char key[64]) {
547 if (!key_str) { errno = EPROTO; return -1; }
548 if (!*key_str) { errno = EPROTO; return -1; }
549 if (*key_str == '@') key_str++;
550 size_t len = strlen(key_str);
551 if (len > 8 && memcmp(key_str + len - 8, ".ed25519", 8) == 0) len -= 8;
552 return sodium_base642bin(
553 (unsigned char *const)key, 64,
554 (const char *const)key_str, len,
555 NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
556}
557
558static jsmntok_t *json_lookup(const char *buf, jsmntok_t *tok, const char *prop, size_t prop_len) {
559 jsmntok_t *end = tok + tok->size + 1;
560 if (tok->type != JSMN_OBJECT) { errno = EPROTO; return NULL; }
561 tok++;
562 while (tok < end) {
563 if (tok + 1 >= end) { errno = EPROTO; return NULL; }
564 if (tok->type == JSMN_STRING
565 && tok->end - tok->start == (int)prop_len
566 && memcmp(buf + tok->start, prop, prop_len) == 0)
567 return tok + 1;
568 tok += tok->size + 1;
569 end += tok->size;
570 }
571 return NULL;
572}
573
574static ssize_t json_get_value(const char *buf, const char *path, const char **value) {
575 static const int num_tokens = 1024;
576 jsmntok_t tokens[num_tokens], *tok = tokens;
577 jsmn_parser parser;
578
579 jsmn_init(&parser);
580 switch (jsmn_parse(&parser, buf, tokens, num_tokens)) {
581 case JSMN_ERROR_NOMEM: errno = ENOMEM; return -1;
582 case JSMN_ERROR_INVAL: errno = EINVAL; return -1;
583 case JSMN_ERROR_PART: errno = EMSGSIZE; return -1;
584 case JSMN_SUCCESS: break;
585 default: errno = EPROTO; return -1;
586 }
587
588 while (*path) {
589 const char *end = strchr(path, '.');
590 size_t part_len = end ? (size_t)end - (size_t)path : strlen(path);
591 tok = json_lookup(buf, tok, path, part_len);
592 if (!tok) { errno = ENOMSG; return -1; }
593 path += part_len;
594 if (*path == '.') path++;
595 }
596
597 *value = buf + tok->start;
598 return tok->end - tok->start;
599}
600
601static void get_app_dir(char *dir, size_t len) {
602 const char *path, *home, *appname;
603 int rc;
604 path = getenv("ssb_path");
605 if (path) {
606 if (strlen(path) > len) errx(1, "ssb_path too long");
607 strncpy(dir, path, len);
608 return;
609 }
610 home = getenv("HOME");
611 if (!home) home = ".";
612 appname = getenv("ssb_appname");
613 if (!appname) appname = "ssb";
614 rc = snprintf(dir, len, "%s/.%s", home, appname);
615 if (rc < 0) err(1, "failed to get app dir");
616 if ((size_t)rc >= len) errx(1, "path to app dir too long");
617}
618
619static ssize_t read_file(char *buf, size_t len, const char *fmt, ...) {
620 va_list ap;
621 int rc;
622 struct stat st;
623 int fd;
624
625 va_start(ap, fmt);
626 rc = vsnprintf(buf, len, fmt, ap);
627 va_end(ap);
628 if (rc < 0) return -1;
629 if ((size_t)rc >= len) { errno = ENAMETOOLONG; return -1; }
630
631 rc = stat(buf, &st);
632 if (rc < 0) return -1;
633 if (st.st_size > (off_t)(len-1)) { errno = EMSGSIZE; return -1; }
634
635 fd = open(buf, O_RDONLY);
636 if (fd < 0) return -1;
637
638 rc = read_all(fd, buf, st.st_size);
639 if (rc < 0) return -1;
640 buf[st.st_size] = '\0';
641
642 close(fd);
643 return st.st_size;
644}
645
646
647static void read_private_key(const char *dir, unsigned char pk[64]) {
648 ssize_t len;
649 char buf[8192];
650 const char *pk_b64;
651 int rc;
652 ssize_t key_len;
653 char *line;
654
655 len = read_file(buf, sizeof(buf), "%s/secret", dir);
656 if (len < 0) err(1, "failed to read secret file");
657
658 // strip comments
659 for (line = buf; *line; ) {
660 if (*line == '#') while (*line && *line != '\n') *line++ = ' ';
661 else while (*line && *line++ != '\n');
662 }
663
664 key_len = json_get_value(buf, "private", &pk_b64);
665 if (key_len < 0) err(1, "unable to read private key");
666
667 if (key_len > 8 && memcmp(pk_b64 + key_len - 8, ".ed25519", 8) == 0)
668 key_len -= 8;
669 rc = sodium_base642bin(
670 (unsigned char *const)pk, 64,
671 (const char *const)pk_b64, key_len,
672 NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
673 if (rc < 0) err(1, "unable to decode private key");
674}
675
676static void increment_nonce(uint8_t nonce[24]) {
677 int i;
678 for (i = 23; i >= 0 && nonce[i] == 0xff; i--) nonce[i] = 0;
679 if (i >= 0) nonce[i]++;
680}
681
682static void bs_write_end_box(struct boxs *bs) {
683 unsigned char boxed[34];
684 int rc = crypto_secretbox_easy(boxed, zeros, 18, bs->nonce1, bs->encrypt_key);
685 if (rc < 0) errx(1, "failed to box packet end header");
686 increment_nonce(bs->nonce1);
687 increment_nonce(bs->nonce2);
688 rc = write_all(bs->s, boxed, 34);
689 if (rc < 0) err(1, "failed to write boxed end header");
690}
691
692static void bs_write_packet(struct boxs *bs, const unsigned char *buf, uint16_t len) {
693 size_t boxed_len = len + 34;
694 unsigned char boxed[boxed_len];
695 increment_nonce(bs->nonce2);
696 int rc = crypto_secretbox_easy(boxed + 18, buf, len, bs->nonce2, bs->encrypt_key);
697 if (rc < 0) errx(1, "failed to box packet data");
698 struct boxs_header header;
699 header.len = htons(len);
700 memcpy(header.mac, boxed + 18, 16);
701 rc = crypto_secretbox_easy(boxed, (unsigned char *)&header, 18, bs->nonce1, bs->encrypt_key);
702 if (rc < 0) errx(1, "failed to box packet header");
703 increment_nonce(bs->nonce1);
704 increment_nonce(bs->nonce1);
705 increment_nonce(bs->nonce2);
706 rc = write_all(bs->s, boxed, boxed_len);
707 if (rc < 0) err(1, "failed to write boxed packet");
708}
709
710static void bs_end(struct boxs *bs) {
711 if (bs->wrote_goodbye) return;
712 bs->wrote_goodbye = true;
713 if (!bs->noauth) {
714 bs_write_end_box(bs);
715 }
716 shutdown(bs->s, SHUT_WR);
717}
718
719static int bs_read_packet(struct boxs *bs, void *buf, size_t *lenp) {
720 int rc;
721 if (bs->noauth) {
722 rc = read_some(bs->s, buf, lenp);
723 if (rc < 0 && errno == EPIPE) return -1;
724 if (rc < 0) err(1, "failed to read packet data");
725 return 0;
726 }
727 unsigned char boxed_header[34];
728 struct boxs_header header;
729 rc = read_all(bs->s, boxed_header, 34);
730 if (rc < 0 && errno == EPIPE) errx(1, "unexpected end of parent stream");
731 if (rc < 0) err(1, "failed to read boxed packet header");
732 rc = crypto_secretbox_open_easy((unsigned char *)&header, boxed_header, 34, bs->rx_nonce, bs->decrypt_key);
733 if (rc < 0) errx(1, "failed to unbox packet header");
734 increment_nonce(bs->rx_nonce);
735 if (header.len == 0 && !memcmp(header.mac, zeros, 16)) { errno = EPIPE; return -1; }
736 size_t len = ntohs(header.len);
737 if (len > BOXS_MAXLEN) errx(1, "received boxed packet too large");
738 unsigned char boxed_data[len + 16];
739 rc = read_all(bs->s, boxed_data + 16, len);
740 if (rc < 0) err(1, "failed to read boxed packet data");
741 memcpy(boxed_data, header.mac, 16);
742 rc = crypto_secretbox_open_easy(buf, boxed_data, len+16, bs->rx_nonce, bs->decrypt_key);
743 if (rc < 0) errx(1, "failed to unbox packet data");
744 increment_nonce(bs->rx_nonce);
745 *lenp = len;
746 return 0;
747}
748
749static int bs_read(struct boxs *bs, char *buf, size_t len) {
750 if (bs->noauth) {
751 int rc = read_all(bs->s, buf, len);
752 if (rc < 0) err(1, "failed to read packet data");
753 return 0;
754 }
755 size_t remaining;
756 while (len > 0) {
757 remaining = bs->rx_buf_len > len ? len : bs->rx_buf_len;
758 if (buf) memcpy(buf, bs->rx_buf + bs->rx_buf_pos, remaining);
759 bs->rx_buf_len -= remaining;
760 bs->rx_buf_pos += remaining;
761 len -= remaining;
762 buf += remaining;
763 if (len == 0) return 0;
764 if (bs_read_packet(bs, bs->rx_buf, &bs->rx_buf_len) < 0) return -1;
765 bs->rx_buf_pos = 0;
766 }
767 return 0;
768}
769
770static enum stream_state bs_read_out_1(struct boxs *bs, int fd) {
771 size_t buf[4096];
772 size_t len = sizeof(buf);
773 int rc;
774 rc = bs_read_packet(bs, buf, &len);
775 if (rc < 0 && errno == EPIPE) {
776 bs_end(bs);
777 return stream_state_ended_ok;
778 }
779 if (rc < 0) return stream_state_ended_error;
780 rc = write_all(fd, buf, len);
781 if (rc < 0) return stream_state_ended_error;
782 return stream_state_open;
783}
784
785static int bs_read_out(struct boxs *bs, int fd, size_t len) {
786 size_t chunk;
787 char buf[4096];
788 int rc;
789 while (len > 0) {
790 chunk = len > sizeof(buf) ? sizeof(buf) : len;
791 rc = bs_read(bs, buf, chunk);
792 if (rc < 0) return -1;
793 rc = write_all(fd, buf, chunk);
794 if (rc < 0) return -1;
795 len -= chunk;
796 }
797 return 0;
798}
799
800static int bs_read_error(struct boxs *bs, int errfd, enum pkt_flags flags, size_t len, bool no_newline) {
801 // suppress printing "true" indicating end without error
802 if (flags & pkt_flags_json && len == 4) {
803 char buf[4];
804 if (bs_read(bs, buf, 4) < 0) return -1;
805 if (strncmp(buf, "true", 4) == 0) {
806 return 0;
807 }
808 if (write_all(errfd, buf, 4) < 0) return -1;
809 } else {
810 if (bs_read_out(bs, errfd, len) < 0) return -1;
811 }
812 if (flags & (pkt_flags_json | pkt_flags_string) && !no_newline) {
813 if (write_buf(errfd, "\n") < 0) return -1;
814 }
815 return 1;
816}
817
818static void bs_write(struct boxs *bs, const unsigned char *buf, size_t len) {
819 if (bs->noauth) {
820 int rc = write_all(bs->s, buf, len);
821 if (rc < 0) err(1, "failed to write packet");
822 return;
823 }
824 while (len > 0) {
825 size_t l = len > BOXS_MAXLEN ? BOXS_MAXLEN : len;
826 bs_write_packet(bs, buf, l);
827 len -= l;
828 buf += l;
829 }
830}
831
832static enum stream_state bs_write_in_1(struct boxs *bs, int fd) {
833 unsigned char buf[4096];
834 ssize_t sz = read(fd, buf, sizeof(buf));
835 if (sz < 0) err(1, "read");
836 if (sz == 0) {
837 bs_end(bs);
838 return stream_state_ended_ok;
839 }
840 bs_write(bs, buf, sz);
841 return stream_state_open;
842}
843
844static void ps_write(struct boxs *bs, const char *data, size_t len, enum pkt_type type, int req_id, bool stream, bool end) {
845 size_t out_len = 9 + len;
846 unsigned char out_buf[out_len];
847 uint32_t len_n = htonl(len);
848 int32_t req_n = htonl(req_id);
849 out_buf[0] = (stream << 3) | (end << 2) | (type & 3);
850 memcpy(out_buf+1, &len_n, 4);
851 memcpy(out_buf+5, &req_n, 4);
852 memcpy(out_buf+9, data, len);
853 bs_write(bs, out_buf, out_len);
854}
855
856static void ps_goodbye(struct boxs *bs) {
857 if (bs->wrote_goodbye) return;
858 bs->wrote_goodbye = true;
859 bs_write(bs, zeros, 9);
860}
861
862static int ps_read_header(struct boxs *bs, size_t *len, int *req_id, enum pkt_flags *flags) {
863 char buf[9];
864 uint32_t len_n;
865 int32_t req_n;
866 if (bs_read(bs, buf, sizeof(buf)) < 0) return -1;
867 memcpy(&len_n, buf+1, 4);
868 memcpy(&req_n, buf+5, 4);
869 if (len) *len = ntohl(len_n);
870 if (req_id) *req_id = ntohl(req_n);
871 if (flags) *flags = buf[0];
872 return 0;
873}
874
875static void muxrpc_call(struct boxs *bs, const char *method, const char *argument, enum muxrpc_type type, const char *typestr, int req_id) {
876 char req[33792]; // 32768 max message value size + 1024 extra
877 ssize_t reqlen;
878 bool is_request = type == muxrpc_type_async;
879
880 if (is_request) {
881 reqlen = snprintf(req, sizeof(req),
882 "{\"name\":%s,\"args\":%s}",
883 method, argument);
884 } else {
885 reqlen = snprintf(req, sizeof(req),
886 "{\"name\":%s,\"args\":%s,\"type\":\"%s\"}",
887 method, argument, typestr);
888 }
889 if (reqlen < 0) err(1, "failed to construct request");
890 if ((size_t)reqlen >= sizeof(req)) errx(1, "request too large");
891
892 ps_write(bs, req, reqlen, pkt_type_json, req_id, !is_request, false);
893}
894
895static int bs_passthrough(struct boxs *bs, int infd, int outfd) {
896 int rc;
897 fd_set rd;
898 int sfd = bs->s;
899 int maxfd = infd > sfd ? infd : sfd;
900 enum stream_state in = stream_state_open;
901 enum stream_state out = stream_state_open;
902
903 while (out == stream_state_open) {
904 FD_ZERO(&rd);
905 if (in == stream_state_open) FD_SET(infd, &rd);
906 if (out == stream_state_open) FD_SET(sfd, &rd);
907 rc = select(maxfd + 1, &rd, 0, 0, NULL);
908 if (rc < 0) err(1, "select");
909 if (FD_ISSET(infd, &rd)) in = bs_write_in_1(bs, infd);
910 if (FD_ISSET(sfd, &rd)) out = bs_read_out_1(bs, outfd);
911 }
912
913 return in != stream_state_ended_error && out == stream_state_ended_ok ? 0 :
914 in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1;
915}
916
917static void ps_reject(struct boxs *bs, size_t len, int32_t req, enum pkt_flags flags) {
918 // ignore the packet. if this is a request, the substream on the other end
919 // will just have to wait until the rpc connection closes.
920 (void)req;
921 (void)flags;
922 write_buf(STDERR_FILENO, "ignoring packet: ");
923 int rc = bs_read_out(bs, STDERR_FILENO, len);
924 if (rc < 0) err(1, "bs_read_out");
925 write_buf(STDERR_FILENO, "\n");
926}
927
928static enum stream_state muxrpc_read_source_1(struct boxs *bs, int outfd, int req_id, bool no_newline) {
929 enum pkt_flags flags;
930 size_t len;
931 int32_t req;
932 int rc = ps_read_header(bs, &len, &req, &flags);
933 if (rc < 0) err(1, "ps_read_header");
934 if (req == 0 && len == 0) {
935 if (bs->wrote_goodbye) return stream_state_ended_ok;
936 warnx("unexpected end of parent stream");
937 return stream_state_ended_error;
938 }
939 if (req != -req_id) {
940 ps_reject(bs, len, req, flags);
941 return stream_state_open;
942 }
943 if (flags & pkt_flags_end) {
944 rc = bs_read_error(bs, STDERR_FILENO, flags, len, no_newline);
945 if (rc < 0) err(1, "bs_read_error");
946 if (rc == 1) return stream_state_ended_error;
947 return stream_state_ended_ok;
948 }
949 rc = bs_read_out(bs, outfd, len);
950 if (rc < 0) err(1, "bs_read_out");
951 if (flags & (pkt_flags_json | pkt_flags_string) && !no_newline) {
952 rc = write_buf(outfd, "\n");
953 if (rc < 0) err(1, "write_buf");
954 }
955 return stream_state_open;
956}
957
958static int muxrpc_read_source(struct boxs *bs, int outfd, int req_id, bool no_newline) {
959 enum stream_state state;
960 while ((state = muxrpc_read_source_1(bs, outfd, req_id, no_newline)) == stream_state_open);
961 return state == stream_state_ended_ok ? 0 :
962 state == stream_state_ended_error ? 2 : 1;
963}
964
965static int muxrpc_read_async(struct boxs *bs, int outfd, int req_id, bool no_newline) {
966 enum pkt_flags flags;
967 size_t len;
968 int32_t req;
969 int rc;
970
971 while (1) {
972 rc = ps_read_header(bs, &len, &req, &flags);
973 if (rc < 0) err(1, "ps_read_header");
974 if (req == -req_id) break;
975 if (req == 0 && len == 0) errx(1, "unexpected end of parent stream");
976 ps_reject(bs, len, req, flags);
977 }
978 if (flags & pkt_flags_end) {
979 rc = bs_read_error(bs, STDERR_FILENO, flags, len, no_newline);
980 if (rc < 0) err(1, "bs_read_error");
981 if (rc == 1) return 2;
982 return 1;
983 }
984 rc = bs_read_out(bs, outfd, len);
985 if (rc < 0) err(1, "bs_read_out");
986 if (flags & (pkt_flags_json | pkt_flags_string) && !no_newline) {
987 rc = write_buf(outfd, "\n");
988 if (rc < 0) err(1, "write_buf");
989 }
990 return 0;
991}
992
993static enum stream_state muxrpc_write_sink_1(struct boxs *bs, int infd,
994 enum pkt_type ptype, int req_id) {
995 char buf[4096];
996 ssize_t sz = read(infd, buf, sizeof(buf));
997 if (sz < 0) err(1, "read");
998 if (sz == 0) {
999 ps_write(bs, "true", 4, pkt_type_json, req_id, true, true);
1000 return stream_state_ended_ok;
1001 }
1002 ps_write(bs, buf, sz, ptype, req_id, true, false);
1003 return stream_state_open;
1004}
1005
1006static enum stream_state muxrpc_write_sink_1_hashed(struct boxs *bs, int infd,
1007 crypto_hash_sha256_state *hash_state, int req_id) {
1008 int rc;
1009 unsigned char buf[4096];
1010 ssize_t sz = read(infd, buf, sizeof(buf));
1011 if (sz < 0) err(1, "read");
1012 if (sz == 0) {
1013 ps_write(bs, "true", 4, pkt_type_json, req_id, true, true);
1014 return stream_state_ended_ok;
1015 }
1016 rc = crypto_hash_sha256_update(hash_state, buf, sz);
1017 if (rc < 0) errx(1, "hash update failed");
1018 ps_write(bs, (char *)buf, sz, pkt_type_buffer, req_id, true, false);
1019 return stream_state_open;
1020}
1021
1022static int muxrpc_write_sink(struct boxs *bs, int infd, enum pkt_type ptype, int req_id, bool no_newline) {
1023 int rc;
1024 fd_set rd;
1025 int sfd = bs->s;
1026 int maxfd = infd > sfd ? infd : sfd;
1027 enum stream_state in = stream_state_open;
1028 enum stream_state out = stream_state_open;
1029
1030 while (out == stream_state_open) {
1031 FD_ZERO(&rd);
1032 if (in == stream_state_open) FD_SET(infd, &rd);
1033 if (out == stream_state_open) FD_SET(sfd, &rd);
1034 rc = select(maxfd + 1, &rd, 0, 0, NULL);
1035 if (rc < 0) err(1, "select");
1036 if (FD_ISSET(infd, &rd)) in = muxrpc_write_sink_1(bs, infd, ptype, req_id);
1037 if (FD_ISSET(sfd, &rd)) out = muxrpc_read_source_1(bs, -1, req_id, no_newline);
1038 }
1039
1040 return in == stream_state_ended_ok && out == stream_state_ended_ok ? 0 :
1041 in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1;
1042}
1043
1044static int muxrpc_write_blob_add(struct boxs *bs, int infd, int outfd, int req_id, bool no_newline) {
1045 int rc;
1046 fd_set rd;
1047 int sfd = bs->s;
1048 int maxfd = infd > sfd ? infd : sfd;
1049 enum stream_state in = stream_state_open;
1050 enum stream_state out = stream_state_open;
1051 crypto_hash_sha256_state hash_state;
1052 unsigned char hash[32];
1053 char id[54] = "&";
1054
1055 rc = crypto_hash_sha256_init(&hash_state);
1056 if (rc < 0) { errno = EINVAL; return -1; }
1057
1058 while (out == stream_state_open) {
1059 FD_ZERO(&rd);
1060 if (in == stream_state_open) FD_SET(infd, &rd);
1061 if (out == stream_state_open) FD_SET(sfd, &rd);
1062 rc = select(maxfd + 1, &rd, 0, 0, NULL);
1063 if (rc < 0) err(1, "select");
1064 if (FD_ISSET(infd, &rd)) in = muxrpc_write_sink_1_hashed(bs, infd, &hash_state, req_id);
1065 if (FD_ISSET(sfd, &rd)) out = muxrpc_read_source_1(bs, -1, req_id, no_newline);
1066 }
1067
1068 rc = crypto_hash_sha256_final(&hash_state, hash);
1069 if (rc < 0) errx(1, "hash finalize failed");
1070
1071 (void)sodium_bin2base64(id+1, sizeof(id)-1, hash, 32, sodium_base64_VARIANT_ORIGINAL);
1072 strcpy(id + 45, ".sha256\n");
1073 rc = write_all(outfd, id, sizeof(id)-1);
1074 if (rc < 0) err(1, "writing hash failed");
1075
1076 return in == stream_state_ended_ok && out == stream_state_ended_ok ? 0 :
1077 in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1;
1078}
1079
1080static int muxrpc_duplex(struct boxs *bs, int infd, int outfd, enum pkt_type in_ptype, int req_id, bool no_newline) {
1081 int rc;
1082 fd_set rd;
1083 int sfd = bs->s;
1084 int maxfd = infd > sfd ? infd : sfd;
1085 enum stream_state in = stream_state_open;
1086 enum stream_state out = stream_state_open;
1087
1088 while (out == stream_state_open) {
1089 FD_ZERO(&rd);
1090 if (in == stream_state_open) FD_SET(infd, &rd);
1091 if (out == stream_state_open) FD_SET(sfd, &rd);
1092 rc = select(maxfd + 1, &rd, 0, 0, NULL);
1093 if (rc < 0) err(1, "select");
1094 if (FD_ISSET(infd, &rd)) in = muxrpc_write_sink_1(bs, infd, in_ptype, req_id);
1095 if (FD_ISSET(sfd, &rd)) out = muxrpc_read_source_1(bs, outfd, req_id, no_newline);
1096 }
1097
1098 return in == stream_state_ended_ok && out == stream_state_ended_ok ? 0 :
1099 in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1;
1100}
1101
1102static int method_to_json(char *out, size_t outlen, const char *str) {
1103 // blobs.get => ["blobs", "get"]
1104 size_t i = 0;
1105 char c;
1106 if (i+2 > outlen) return -1;
1107 out[i++] = '[';
1108 out[i++] = '"';
1109 while ((c = *str++)) {
1110 if (c == '.') {
1111 if (i+3 > outlen) return -1;
1112 out[i++] = '"';
1113 out[i++] = ',';
1114 out[i++] = '"';
1115 } else if (c == '"') {
1116 if (i+2 > outlen) return -1;
1117 out[i++] = '\\';
1118 out[i++] = '"';
1119 } else {
1120 if (i+1 > outlen) return -1;
1121 out[i++] = c;
1122 }
1123 }
1124 if (i+3 > outlen) return -1;
1125 out[i++] = '"';
1126 out[i++] = ']';
1127 out[i++] = '\0';
1128 return i;
1129}
1130
1131static int args_to_json_length(int argc, char *argv[], bool encode_strings) {
1132 int i = 0;
1133 int len = 3; // "[]\0"
1134 for (i = 0; i < argc; i++) {
1135 if (!encode_strings) {
1136 len += strlen(argv[i])+1;
1137 } else {
1138 len += 3; // "\"\","
1139 char *arg = argv[i], c;
1140 while ((c = *arg++)) switch (c) {
1141 case '"': len += 2; break;
1142 case '\\': len += 2; break;
1143 default: len++;
1144 }
1145 }
1146 }
1147 return len;
1148}
1149
1150static int args_to_json(char *out, size_t outlen, unsigned int argc, char *argv[], bool encode_strings) {
1151 size_t i = 0;
1152 size_t j;
1153 if (i+1 > outlen) return -1;
1154 out[i++] = '[';
1155 for (j = 0; j < argc; j++) {
1156 if (!encode_strings) {
1157 size_t len = strlen(argv[j]);
1158 if (j > 0) out[i++] = ',';
1159 if (i+len > outlen) return -1;
1160 strncpy(out+i, argv[j], len);
1161 i += len;
1162 } else {
1163 char *arg = argv[j];
1164 char c;
1165 if (j > 0) {
1166 if (i+1 > outlen) return -1;
1167 out[i++] = ',';
1168 }
1169 if (i+1 > outlen) return -1;
1170 out[i++] = '"';
1171 while ((c = *arg++)) {
1172 if (i+2 > outlen) return -1;
1173 if (c == '"' || c == '\\') out[i++] = '\\';
1174 out[i++] = c;
1175 }
1176 if (i+1 > outlen) return -1;
1177 out[i++] = '"';
1178 }
1179 }
1180 if (i+2 > outlen) return -1;
1181 out[i++] = ']';
1182 out[i++] = '\0';
1183 return i;
1184}
1185
1186int main(int argc, char *argv[]) {
1187 int i, s, infd, outfd, rc;
1188 const char *key = NULL;
1189 const char *keypair_seed_str = NULL;
1190 const char *host = NULL;
1191 const char *port = "8008";
1192 const char *typestr = NULL, *methodstr = NULL;
1193 const char *shs_cap_key_str = NULL;
1194 const char *socket_path = NULL;
1195 size_t argument_len;
1196 unsigned char private_key[64];
1197 unsigned char public_key[32];
1198 unsigned char remote_key[32];
1199 unsigned char shs_cap_key[32];
1200 enum muxrpc_type type;
1201 enum pkt_type ptype = pkt_type_buffer;
1202 char method[256];
1203 char app_dir[_POSIX_PATH_MAX];
1204 ssize_t len;
1205 bool test = false;
1206 bool noauth = false;
1207 bool no_newline = false;
1208 bool raw = false;
1209 bool host_arg = false;
1210 bool port_arg = false;
1211 bool key_arg = false;
1212 bool shs_cap_key_str_arg = false;
1213 bool ipv4_arg = false;
1214 bool ipv6_arg = false;
1215 bool passthrough = false;
1216 bool strings = false;
1217 bool daemon = false;
1218 enum ip_family ip_family;
1219
1220 get_app_dir(app_dir, sizeof(app_dir));
1221
1222 char config_buf[8192];
1223 len = read_file(config_buf, sizeof(config_buf), "%s/config", app_dir);
1224 if (len > 0) {
1225 ssize_t key_len = json_get_value(config_buf, "key", &key);
1226 ssize_t host_len = json_get_value(config_buf, "host", &host);
1227 ssize_t port_len = json_get_value(config_buf, "port", &port);
1228 ssize_t shs_cap_len = json_get_value(config_buf, "caps.shs", &shs_cap_key_str);
1229 if (key_len >= 0) ((char *)key)[key_len] = '\0';
1230 if (host_len >= 0) ((char *)host)[host_len] = '\0';
1231 if (port_len >= 0) ((char *)port)[port_len] = '\0';
1232 if (shs_cap_len >= 0) ((char *)shs_cap_key_str)[shs_cap_len] = '\0';
1233 } else if (len < 0 && errno != ENOENT) {
1234 err(1, "failed to read config");
1235 }
1236
1237 for (i = 1; i < argc && (argv[i][0] == '-'); i++) {
1238 switch (argv[i][1]) {
1239 case 'c': shs_cap_key_str = argv[++i]; shs_cap_key_str_arg = true; break;
1240 case 'j': ptype = pkt_type_json; break;
1241 case 'T': test = true; break;
1242 case 's': host = argv[++i]; host_arg = true; break;
1243 case 'k': key = argv[++i]; key_arg = true; break;
1244 case 'K': keypair_seed_str = argv[++i]; break;
1245 case 'p': port = argv[++i]; port_arg = true; break;
1246 case 'u': socket_path = argv[++i]; break;
1247 case 't': typestr = argv[++i]; break;
1248 case 'n': noauth = true; break;
1249 case '4': ipv4_arg = true; break;
1250 case '6': ipv6_arg = true; break;
1251 case 'd': daemon = true; break;
1252 case 'a': passthrough = true; break;
1253 case 'l': no_newline = true; break;
1254 case 'r': raw = true; no_newline = true; break;
1255 case 'e': strings = true; break;
1256 default: usage();
1257 }
1258 }
1259 if (i < argc) methodstr = argv[i++];
1260 else if (!test && !passthrough) usage();
1261
1262 if (ipv4_arg && ipv6_arg) errx(1, "options -4 and -6 conflict");
1263 ip_family =
1264 ipv4_arg ? ip_family_ipv4 :
1265 ipv6_arg ? ip_family_ipv6 :
1266 ip_family_any;
1267
1268 if (shs_cap_key_str) {
1269 rc = pubkey_decode(shs_cap_key_str, shs_cap_key);
1270 if (rc < 0) err(1, "unable to decode cap key '%s'", shs_cap_key_str);
1271 } else {
1272 memcpy(shs_cap_key, ssb_cap, 32);
1273 }
1274
1275 argument_len = test ? 0 : args_to_json_length(argc-i, argv+i, strings);
1276 char argument[argument_len];
1277
1278 if (passthrough) {
1279 if (methodstr) errx(1, "-a option conflicts with method");
1280 if (typestr) errx(1, "-a option conflicts with -t option");
1281 if (argc-i > 0) errx(1, "-a option conflicts with method arguments");
1282 if (test) errx(1, "-a option conflicts with -T test");
1283
1284 } else if (!test) {
1285 rc = args_to_json(argument, sizeof(argument), argc-i, argv+i, strings);
1286 if (rc < 0) errx(1, "unable to collect arguments");
1287
1288 char manifest_buf[8192];
1289 if (!typestr) {
1290 len = read_file(manifest_buf, sizeof(manifest_buf),
1291 "%s/manifest.json", app_dir);
1292 if (len < 0) err(1, "failed to read manifest file");
1293
1294 ssize_t type_len = json_get_value(manifest_buf, methodstr, &typestr);
1295 if (!typestr && errno == ENOMSG) errx(1,
1296 "unable to find method '%s' in manifest", methodstr);
1297 if (!typestr) err(1, "unable to read manifest %s/%s", manifest_buf, methodstr);
1298 ((char *)typestr)[type_len] = '\0';
1299 }
1300 if (strcmp(typestr, "sync") == 0) type = muxrpc_type_async;
1301 else if (strcmp(typestr, "async") == 0) type = muxrpc_type_async;
1302 else if (strcmp(typestr, "sink") == 0) type = muxrpc_type_sink;
1303 else if (strcmp(typestr, "source") == 0) type = muxrpc_type_source;
1304 else if (strcmp(typestr, "duplex") == 0) type = muxrpc_type_duplex;
1305 else errx(1, "type must be one of <async|sink|source|duplex>");
1306
1307 rc = method_to_json(method, sizeof(method), methodstr);
1308 if (rc < 0) errx(0, "unable to convert method name");
1309 }
1310
1311 if (keypair_seed_str == NULL) {
1312 read_private_key(app_dir, private_key);
1313 memcpy(public_key, private_key+32, 32);
1314 } else if (strlen(keypair_seed_str) > 55) {
1315 rc = seckey_decode(keypair_seed_str, private_key);
1316 if (rc < 0) err(1, "unable to decode private key");
1317 memcpy(public_key, private_key+32, 32);
1318 } else if (keypair_seed_str) {
1319 unsigned char seed[crypto_sign_SEEDBYTES];
1320 unsigned char ed25519_skpk[crypto_sign_ed25519_SECRETKEYBYTES];
1321
1322 rc = pubkey_decode(keypair_seed_str, ed25519_skpk);
1323 if (rc < 0) err(1, "unable to decode private key");
1324 rc = crypto_sign_ed25519_sk_to_seed(seed, ed25519_skpk);
1325 if (rc < 0) err(1, "unable to convert private key to seed");
1326 rc = crypto_sign_seed_keypair(public_key, private_key, seed);
1327 if (rc < 0) err(1, "unable to generate keypair from seed");
1328 }
1329
1330 if (key) {
1331 rc = pubkey_decode(key, remote_key);
1332 if (rc < 0) err(1, "unable to decode remote key '%s'", key);
1333 } else {
1334 memcpy(remote_key, public_key, 32);
1335 }
1336
1337 bool implied_tcp = host_arg || port_arg || ipv4_arg || ipv6_arg;
1338 bool implied_auth = key_arg || keypair_seed_str || shs_cap_key_str_arg || test;
1339
1340 if (test) {
1341 infd = STDIN_FILENO;
1342 outfd = STDOUT_FILENO;
1343 s = -1;
1344
1345 } else if (socket_path) {
1346 if (implied_tcp) errx(1, "-u option conflicts with host/port options");
1347 s = unix_connect(socket_path, daemon);
1348 if (s < 0) err(1, "unix_connect");
1349 infd = outfd = s;
1350
1351 } else if (!implied_tcp && !implied_auth) {
1352 char socket_path_buf[_POSIX_PATH_MAX];
1353 rc = get_socket_path(socket_path_buf, sizeof(socket_path_buf), app_dir, daemon);
1354 if (rc < 0 && noauth) err(1, "get_socket_path");
1355 if (rc < 0) goto do_tcp;
1356 s = unix_connect(socket_path_buf, daemon);
1357 if (s < 0 && noauth) err(1, "unix_connect");
1358 if (s < 0) goto do_tcp;
1359 noauth = true;
1360 infd = outfd = s;
1361
1362 } else {
1363do_tcp:
1364 s = tcp_connect(host, port, ip_family, daemon);
1365 if (s < 0) err(1, "tcp_connect");
1366 infd = outfd = s;
1367 }
1368
1369 struct boxs bs;
1370 if (noauth) {
1371 bs.s = s;
1372 bs.noauth = true;
1373 if (implied_auth) errx(1, "-n option conflicts with -k, -K, -c and -T options.");
1374 } else {
1375 shs_connect(s, infd, outfd, public_key, private_key, shs_cap_key, remote_key, &bs, !daemon, key_arg);
1376 }
1377
1378 if (test) {
1379 rc = write_all(outfd, bs.encrypt_key, sizeof(bs.encrypt_key));
1380 rc |= write_all(outfd, bs.nonce1, sizeof(bs.nonce1));
1381 rc |= write_all(outfd, bs.decrypt_key, sizeof(bs.decrypt_key));
1382 rc |= write_all(outfd, bs.rx_nonce, sizeof(bs.rx_nonce));
1383 if (rc < 0) err(1, "failed to write handshake result");
1384 return 0;
1385 }
1386
1387 if (passthrough) {
1388 rc = bs_passthrough(&bs, STDIN_FILENO, STDOUT_FILENO);
1389 close(s);
1390 return rc;
1391 }
1392
1393 muxrpc_call(&bs, method, argument, type, typestr, 1);
1394
1395 if (raw) {
1396 struct termios raw_tc;
1397 rc = tcgetattr(STDIN_FILENO, &orig_tc);
1398 if (rc < 0) warn("tcgetattr");
1399 raw_tc = orig_tc;
1400 raw_tc.c_lflag &= ~(ICANON | ECHO);
1401 rc = tcsetattr(STDIN_FILENO, TCSANOW, &raw_tc);
1402 if (rc < 0) warn("tcgetattr");
1403 rc = atexit(reset_termios);
1404 if (rc < 0) warn("atexit");
1405 }
1406
1407 switch (type) {
1408 case muxrpc_type_async:
1409 rc = muxrpc_read_async(&bs, STDOUT_FILENO, 1, no_newline);
1410 break;
1411 case muxrpc_type_source:
1412 rc = muxrpc_read_source(&bs, STDOUT_FILENO, 1, no_newline);
1413 break;
1414 case muxrpc_type_sink:
1415 if (!strcmp(methodstr, "blobs.add")) {
1416 rc = muxrpc_write_blob_add(&bs, STDIN_FILENO, STDOUT_FILENO, 1, no_newline);
1417 } else {
1418 rc = muxrpc_write_sink(&bs, STDIN_FILENO, ptype, 1, no_newline);
1419 }
1420 break;
1421 case muxrpc_type_duplex:
1422 rc = muxrpc_duplex(&bs, STDIN_FILENO, STDOUT_FILENO, ptype, 1, no_newline);
1423 break;
1424 }
1425
1426 ps_goodbye(&bs);
1427 bs_end(&bs);
1428 close(s);
1429 return rc;
1430}
1431

Built with git-ssb-web