From 0a1eafebf9031de6ae2153de5539b4b151496dc5 Mon Sep 17 00:00:00 2001 From: cel Date: Mon, 24 Sep 2018 18:12:20 -1000 Subject: [PATCH] Auto-detect local noauth socket Attempt to connect to local noauth socket, unless TCP or SHS options are specified. Fall back to TCP+SHS connection, unless noauth option is specified. --- sbotc.1 | 29 +++++++++++++++++++++---- sbotc.c | 65 +++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/sbotc.1 b/sbotc.1 index 4f1fd5b..57aed60 100644 --- a/sbotc.1 +++ b/sbotc.1 @@ -11,7 +11,7 @@ .Op Fl T . .Oo -.Op Fl n +.Fl n | .Op Fl c Ar cap .Op Fl k Ar key @@ -104,11 +104,32 @@ secret-handshake protocol. A map of method names to method types. .It Pa ~/.ssb/config JSON file containing key, host, port, and/or SHS cap key to use if the -.Ar -s , -.Ar -p +.Fl s , +.Fl p or -.Ar -c +.Fl c options are not given, respectively. +.It Pa ~/.ssb/socket +UNIX socket stream file for noauth connections. +If none of the options +.Fl s , +.Fl p , +.Fl u , +.Fl c , +.Fl k , +.Fl K , +.Fl c , +or +.Fl T +are specified, +.Nm +will attempt to connect in noauth mode to this socket file. If the socket file +is not present or the connection fails, +.Nm +will fall back to connecting with TCP and secret-handshake according to the +config file - unless the +.Fl n +option is specified, in which case the command will fail. .El .Pp The base path diff --git a/sbotc.c b/sbotc.c index 8c4b4e9..5a50754 100644 --- a/sbotc.c +++ b/sbotc.c @@ -98,7 +98,7 @@ static const unsigned char ssb_cap[] = { static void usage() { fputs("usage: sbotc [-j] [-T]\n" - " [ [-n] | [-c ] [-k ] [-K ] ]\n" + " [ -n | [-c ] [-k ] [-K ] ]\n" " [ [-s ] [-p ] | [-u ] ]\n" " [-t ] [...]\n", stderr); exit(EXIT_FAILURE); @@ -132,6 +132,31 @@ static int tcp_connect(const char *host, const char *port) { return fd; } +static int unix_connect(const char *path) { + struct sockaddr_un name; + const size_t path_len = strlen(path); + int s, rc; + if (path_len >= sizeof(name.sun_path)-1) errx(1, "socket path too long"); + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) return -1; + memset(&name, 0, sizeof(struct sockaddr_un)); + name.sun_family = AF_UNIX; + strncpy(name.sun_path, path, sizeof(name.sun_path) - 1); + rc = connect(s, (const struct sockaddr *)&name, sizeof name); + if (rc < 0) return -1; + return s; +} + +static int get_socket_path(char *buf, size_t len, const char *app_dir) { + struct stat st; + int sz = snprintf(buf, len-1, "%s/%s", app_dir, "socket"); + if (sz < 0 || sz >= (int)len-1) err(1, "failed to get socket path"); + int rc = stat(buf, &st); + if (rc < 0) return -1; + if (!(st.st_mode & S_IFSOCK)) { errno = EINVAL; return -1; } + return 0; +} + static int read_all(int fd, void *buf, size_t count) { ssize_t nbytes; while (count > 0) { @@ -836,6 +861,7 @@ int main(int argc, char *argv[]) { bool noauth = false; bool host_arg = false; bool port_arg = false; + bool key_arg = false; bool shs_cap_key_str_arg = false; get_app_dir(app_dir, sizeof(app_dir)); @@ -861,7 +887,7 @@ int main(int argc, char *argv[]) { case 'j': ptype = pkt_type_json; break; case 'T': test = true; break; case 's': host = argv[++i]; host_arg = true; break; - case 'k': key = argv[++i]; break; + case 'k': key = argv[++i]; key_arg = true; break; case 'K': keypair_seed_str = argv[++i]; break; case 'p': port = argv[++i]; port_arg = true; break; case 'u': socket_path = argv[++i]; break; @@ -931,27 +957,33 @@ int main(int argc, char *argv[]) { memcpy(remote_key, public_key, 32); } + bool implied_tcp = host_arg || port_arg; + bool implied_auth = key_arg || keypair_seed_str || shs_cap_key_str_arg || test; + if (test) { infd = STDIN_FILENO; outfd = STDOUT_FILENO; s = -1; } else if (socket_path) { - if (port_arg) errx(1, "-p port conflicts with -u socket_path"); - if (host_arg) errx(1, "-s host conflicts with -u socket_path"); - struct sockaddr_un name; - size_t path_len = strlen(socket_path); - if (path_len >= sizeof(name.sun_path)-1) errx(1, "socket path too long"); - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) err(1, "socket"); - memset(&name, 0, sizeof(struct sockaddr_un)); - name.sun_family = AF_UNIX; - strncpy(name.sun_path, socket_path, sizeof(name.sun_path) - 1); - rc = connect(s, (const struct sockaddr *)&name, sizeof name); - if (rc < 0) err(1, "connect"); + if (implied_tcp) errx(1, "-u option conflicts with -s and -p options"); + s = unix_connect(socket_path); + if (s < 0) err(1, "unix_connect"); + infd = outfd = s; + + } else if (!implied_tcp && !implied_auth) { + char socket_path_buf[_POSIX_PATH_MAX]; + rc = get_socket_path(socket_path_buf, sizeof(socket_path_buf), app_dir); + if (rc < 0 && noauth) err(1, "get_socket_path"); + if (rc < 0) goto do_tcp_connect; + s = unix_connect(socket_path_buf); + if (s < 0 && noauth) err(1, "unix_connect"); + if (s < 0) goto do_tcp_connect; + noauth = true; infd = outfd = s; } else { +do_tcp_connect: s = tcp_connect(host, port); if (s < 0) err(1, "tcp_connect"); infd = outfd = s; @@ -961,10 +993,7 @@ int main(int argc, char *argv[]) { if (noauth) { bs.s = s; bs.noauth = true; - if (key) errx(1, "-k keypair_seed conflicts with -n (noauth)"); - if (keypair_seed_str) errx(1, "-K keypair_seed conflicts with -n (noauth)"); - if (shs_cap_key_str_arg) errx(1, "-c cap_key conflicts with -n (noauth)"); - if (test) errx(1, "-n (noauth) conflicts with -T (test shs)"); + if (implied_auth) errx(1, "-n option conflicts with -k, -K, -c and -T options."); } else { shs_connect(s, infd, outfd, public_key, private_key, shs_cap_key, remote_key, &bs); }