int main(int argc, char **argv) { long long r,w; if (argv[0]) if (argv[1]) if (str_equal(argv[1], "-h")) die_usage(); for (;;) { r = readblock(0, buf, BLOCK); if (r == -1) die_fatal("unable to read input", 0); for (;;) { if (r <= 0) goto end; if (buf[r - 1] == '\n') { --r; continue; } if (buf[r - 1] == '\r') { --r; continue; } break; } buf[r] = 0; if (r % 2) { errno = 0; die_fatal("unable to decode from hex", 0); } w = r / 2; if (!hexparse(buf, w, (char *)buf)) { errno = 0; die_fatal("unable to decode from hex", 0); } if (writeall(1, buf, w) == -1) die_fatal("unable to write output", 0); if (r != BLOCK) break; } end: if (fsyncfd(1) == -1) die_fatal("unable to write output", 0); _exit(0); }
int main(int argc,char **argv) { char *d; if (!argv[0]) die_usage(); if (!argv[1]) die_usage(); d = argv[1]; umask(022); if (mkdir(d,0755) == -1) die_fatal("unable to create directory",d,0); if (chdir(d) == -1) die_fatal("unable to chdir to directory",d,0); if (mkdir(".expertsonly",0700) == -1) die_fatal("unable to create directory",d,".expertsonly"); sodium_init(); crypto_box_keypair(pk,sk); create(d,"publickey",pk,sizeof pk); randombytes(noncekey,sizeof noncekey); umask(077); create(d,".expertsonly/secretkey",sk,sizeof sk); create(d,".expertsonly/lock",lock,sizeof lock); create(d,".expertsonly/noncekey",noncekey,sizeof noncekey); create(d,".expertsonly/noncecounter",noncecounter,sizeof noncecounter); return 0; }
int main(int argc, char **argv, char **envp) { if (!argv[0]) die_usage(); if (!argv[1]) die_usage(); if (str_equal(argv[1], "-h")) die_usage(); if (extremesandbox_droproot() == -1) die_fatal("unable to drop root privileges", 0); pathexec_run(argv[1], argv + 1, envp); die_fatal("unable to run", argv[1]); return 111; }
int main(int argc, char **argv) { pid_t pid; int tochild[2] = { -1, -1 }; int fromchild[2] = { -1, -1 }; const char *message; long long messagelen; if (argc < 2) _exit(111); if (!argv[0]) _exit(111); if (!argv[1]) _exit(111); if (!argv[2]) _exit(111); ++argv; message = *argv; messagelen = str_len(message); ++argv; if (pipe(tochild) == -1) _exit(111); if (pipe(fromchild) == -1) _exit(111); pid = fork(); if (pid == -1) _exit(111); if (pid == 0) { close(tochild[1]); close(fromchild[0]); if (dup2(tochild[0], 0) == -1) _exit(111); if (dup2(fromchild[1], 1) == -1) _exit(111); execvp(*argv, argv); _exit(111); } close(tochild[0]); close(fromchild[1]); close(0); if (dup2(fromchild[0], 0) == -1) _exit(111); close(1); if (dup2(tochild[1], 1) == -1) _exit(111); signal(SIGPIPE, SIG_IGN); global_init(); if (!packet_hello_receive()) die_fatal("unable to receive hello-string", 0, 0); if (messagelen) { if (writeall(1, message, messagelen) == -1) die_fatal("unable to write hello-string", 0, 0); if (writeall(1, "\r\n", 2) == -1) die_fatal("unable to write hello-string", 0, 0); } _exit(111); }
static void die(void) { out((unsigned char *)"\n", 1); flush(); if (fsyncfd(1) == -1) die_fatal("unable to write output", 0); _exit(0); }
void clientshorttermnonce_update(void) { ++clientshorttermnonce; if (clientshorttermnonce) return; errno = EPROTO; die_fatal("nonce space expired",0,0); }
int main(int argc, char **argv) { char *x; long long xlen; if (argv[0]) if (argv[1]) if (str_equal(argv[1], "-h")) die_usage(); x = numtostr(0, seconds()); xlen = str_len(x); x[xlen] = '\n'; if (writeall(1, x, xlen + 1) == -1) die_fatal("unable to write output", 0); if (fsyncfd(1) == -1) die_fatal("unable to write output", 0); _exit(0); }
int main(int argc, char **argv) { pid_t pid; int tochild[2] = { -1, -1 }; int fromchild[2] = { -1, -1 }; if (argc < 2) _exit(111); if (!argv[0]) _exit(111); if (!argv[1]) _exit(111); ++argv; if (pipe(tochild) == -1) _exit(111); if (pipe(fromchild) == -1) _exit(111); pid = fork(); if (pid == -1) _exit(111); if (pid == 0) { close(tochild[1]); close(fromchild[0]); close(2); if (dup2(tochild[0], 0) == -1) _exit(111); if (dup2(fromchild[1], 1) == -1) _exit(111); execvp(*argv, argv); _exit(111); } close(tochild[0]); close(fromchild[1]); close(0); if (dup2(fromchild[0], 0) == -1) _exit(111); close(1); if (dup2(tochild[1], 1) == -1) _exit(111); signal(SIGPIPE, SIG_IGN); global_init(); log_init(2, "_tinysshd-printkex", 0, 0); if (!packet_hello_receive()) die_fatal("unable to receive hello-string", 0, 0); if (!packet_hello_send()) die_fatal("unable to send hello-string", 0, 0); if (!_packet_kex_receive()) die_fatal("unable to receive kex-message", 0, 0); _exit(111); }
int main(int argc, char **argv) { long long r, w; if (argv[0]) if (argv[1]) if (str_equal(argv[1], "-h")) die_usage(); for (;;) { r = readblock(0, bufr, sizeof bufr); if (r == -1) die_fatal("unable to read input", 0); if (r == 0) die(); w = (((r * 8) + 4) / 5); if (!base32encode(bufw, w + 1, bufr, r)) { errno = 0; die_fatal("unable to encode to base32", 0); } out(bufw, w); if (r != sizeof bufr) die(); } return 0; }
static unsigned long long readblock(unsigned char *buf, long long len) { long long r, ret = 0; while (len > 0) { r = read(0, (char *)buf, len); if (r < 0) die_fatal("unable to read input", 0); ret += r; if (r == 0 || r == len) break; buf += r; len -= r; } return ret; }
int main(int argc, char **argv) { char *x; const char *keydir = 0; long long i; struct pollfd p[6]; struct pollfd *q; struct pollfd *watch0; struct pollfd *watch1; struct pollfd *watchtochild; struct pollfd *watchfromchild1; struct pollfd *watchfromchild2; struct pollfd *watchselfpipe; int exitsignal, exitcode; signal(SIGPIPE, SIG_IGN); signal(SIGALRM, timeout); log_init(0, "tinysshd", 0, 0); if (argc < 2) die_usage(USAGE); if (!argv[0]) die_usage(USAGE); for (;;) { if (!argv[1]) break; if (argv[1][0] != '-') break; x = *++argv; if (x[0] == '-' && x[1] == 0) break; if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; while (*++x) { if (*x == 'q') { flagverbose = 0; continue; } if (*x == 'Q') { flagverbose = 1; continue; } if (*x == 'v') { if (flagverbose >= 2) flagverbose = 3; else flagverbose = 2; continue; } if (*x == 'o') { cryptotypeselected |= sshcrypto_TYPEOLDCRYPTO; continue; } if (*x == 'O') { cryptotypeselected &= ~sshcrypto_TYPEOLDCRYPTO; continue; } if (*x == 's') { cryptotypeselected |= sshcrypto_TYPENEWCRYPTO; continue; } if (*x == 'S') { cryptotypeselected &= ~sshcrypto_TYPENEWCRYPTO; continue; } if (*x == 'p') { cryptotypeselected |= sshcrypto_TYPEPQCRYPTO; continue; } if (*x == 'P') { cryptotypeselected &= ~sshcrypto_TYPEPQCRYPTO; continue; } if (*x == 'l') { flaglogger = 1; continue; } if (*x == 'L') { flaglogger = 0; continue; } if (*x == 'x') { if (x[1]) { channel_subsystem_add(x + 1); break; } if (argv[1]) { channel_subsystem_add(*++argv); break; } } die_usage(USAGE); } } keydir = *++argv; if (!keydir) die_usage(USAGE); log_init(flagverbose, "tinysshd", 1, flaglogger); connectioninfo(channel.localip, channel.localport, channel.remoteip, channel.remoteport); log_i4("connection from ", channel.remoteip, ":", channel.remoteport); channel_subsystem_log(); global_init(); blocking_disable(0); blocking_disable(1); blocking_disable(2); /* get server longterm keys */ fdwd = open_cwd(); if (fdwd == -1) die_fatal("unable to open current directory", 0, 0); if (chdir(keydir) == -1) die_fatal("unable to chdir to", keydir, 0); for (i = 0; sshcrypto_keys[i].name; ++i) sshcrypto_keys[i].sign_flagserver |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_keys[i].name; ++i) sshcrypto_keys[i].sign_flagclient |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_kexs[i].name; ++i) sshcrypto_kexs[i].flagenabled |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_ciphers[i].name; ++i) sshcrypto_ciphers[i].flagenabled |= sshcrypto_ciphers[i].cryptotype & cryptotypeselected; /* read public keys */ for (i = 0; sshcrypto_keys[i].name; ++i) { if (!sshcrypto_keys[i].sign_flagserver) continue; if (load(sshcrypto_keys[i].sign_publickeyfilename, sshcrypto_keys[i].sign_publickey, sshcrypto_keys[i].sign_publickeybytes) == -1) { sshcrypto_keys[i].sign_flagserver = 0; if (errno == ENOENT) continue; die_fatal("unable to read public key from file", keydir, sshcrypto_keys[i].sign_publickeyfilename); } } if (fchdir(fdwd) == -1) die_fatal("unable to change directory to working directory", 0, 0); close(fdwd); /* set timeout */ alarm(60); /* send and receive hello */ if (!packet_hello_send()) die_fatal("unable to send hello-string", 0, 0); if (!packet_hello_receive()) die_fatal("unable to receive hello-string", 0, 0); /* send and receive kex */ if (!packet_kex_send()) die_fatal("unable to send kex-message", 0, 0); if (!packet_kex_receive()) die_fatal("unable to receive kex-message", 0, 0); rekeying: /* rekeying */ alarm(60); if (packet.flagrekeying == 1) { buf_purge(&packet.kexrecv); buf_put(&packet.kexrecv, b1.buf, b1.len); if (!packet_kex_send()) die_fatal("unable to send kex-message", 0, 0); } /* send and receive kexdh */ if (!packet_kexdh(keydir, &b1, &b2)) die_fatal("unable to subprocess kexdh", 0, 0); if (packet.flagkeys) log_d1("rekeying: done"); packet.flagkeys = 1; /* note: comunication is encrypted */ /* authentication + authorization */ if (packet.flagauthorized == 0) { if (!packet_auth(&b1, &b2)) die_fatal("authentication failed", 0, 0); packet.flagauthorized = 1; } /* note: user is authenticated and authorized */ alarm(3600); /* main loop */ for (;;) { if (channel_iseof()) if (!packet.sendbuf.len) if (packet.flagchanneleofreceived) break; watch0 = watch1 = 0; watchtochild = watchfromchild1 = watchfromchild2 = 0; watchselfpipe = 0; q = p; if (packet_sendisready()) { watch1 = q; q->fd = 1; q->events = POLLOUT; ++q; } if (packet_recvisready()) { watch0 = q; q->fd = 0; q->events = POLLIN; ++q; } if (channel_writeisready()) { watchtochild = q; q->fd = channel_getfd0(); q->events = POLLOUT; ++q; } if (channel_readisready() && packet_putisready()) { watchfromchild1 = q; q->fd = channel_getfd1(); q->events = POLLIN; ++q; } if (channel_extendedreadisready() && packet_putisready()) { watchfromchild2 = q; q->fd = channel_getfd2(); q->events = POLLIN; ++q; } if (selfpipe[0] != -1) { watchselfpipe = q; q->fd = selfpipe[0]; q->events = POLLIN; ++q; } if (poll(p, q - p, 60000) < 0) { watch0 = watch1 = 0; watchtochild = watchfromchild1 = watchfromchild2 = 0; watchselfpipe = 0; } else { if (watch0) if (!watch0->revents) watch0 = 0; if (watch1) if (!watch1->revents) watch1 = 0; if (watchfromchild1) if (!watchfromchild1->revents) watchfromchild1 = 0; if (watchfromchild2) if (!watchfromchild2->revents) watchfromchild2 = 0; if (watchtochild) if (!watchtochild->revents) watchtochild = 0; if (watchselfpipe) if (!watchselfpipe->revents) watchselfpipe = 0; } if (watchtochild) { /* write data to child */ if (!channel_write()) die_fatal("unable to write data to child", 0, 0); /* try to adjust window */ if (!packet_channel_send_windowadjust(&b1)) die_fatal("unable to send data to network", 0, 0); } /* read data from child */ if (watchfromchild1) packet_channel_send_data(&b2); if (watchfromchild2) packet_channel_send_extendeddata(&b2); /* check child */ if (channel_iseof()) { if (selfpipe[0] == -1) if (open_pipe(selfpipe) == -1) die_fatal("unable to open pipe", 0, 0); signal(SIGCHLD, trigger); if (channel_waitnohang(&exitsignal, &exitcode)) { packet_channel_send_eof(&b2); if (!packet_channel_send_close(&b2, exitsignal, exitcode)) die_fatal("unable to close channel", 0, 0); } } /* send data to network */ if (watch1) if (!packet_send()) die_fatal("unable to send data to network", 0, 0); /* receive data from network */ if (watch0) { alarm(3600); /* refresh timeout */ if (!packet_recv()) { if (channel_iseof()) break; /* XXX */ die_fatal("unable to receive data from network", 0, 0); } } /* process packets */ for (;;) { if (!packet_get(&b1, 0)) { if (!errno) break; die_fatal("unable to get packets from network", 0, 0); } if (b1.len < 1) break; /* XXX */ switch (b1.buf[0]) { case SSH_MSG_CHANNEL_OPEN: if (!packet_channel_open(&b1, &b2)) die_fatal("unable to open channel", 0, 0); break; case SSH_MSG_CHANNEL_REQUEST: if (!packet_channel_request(&b1, &b2)) die_fatal("unable to handle channel-request", 0, 0); break; case SSH_MSG_CHANNEL_DATA: if (!packet_channel_recv_data(&b1)) die_fatal("unable to handle channel-data", 0, 0); break; case SSH_MSG_CHANNEL_EXTENDED_DATA: if (!packet_channel_recv_extendeddata(&b1)) die_fatal("unable to handle channel-extended-data", 0, 0); break; case SSH_MSG_CHANNEL_WINDOW_ADJUST: if (!packet_channel_recv_windowadjust(&b1)) die_fatal("unable to handle channel-window-adjust", 0, 0); break; case SSH_MSG_CHANNEL_EOF: if (!packet_channel_recv_eof(&b1)) die_fatal("unable to handle channel-eof", 0, 0); break; case SSH_MSG_CHANNEL_CLOSE: if (!packet_channel_recv_close(&b1)) die_fatal("unable to handle channel-close", 0, 0); break; case SSH_MSG_KEXINIT: goto rekeying; default: if (!packet_unimplemented(&b1)) die_fatal("unable to send SSH_MSG_UNIMPLEMENTED message", 0, 0); } } } log_i1("finished"); global_die(0); return 111; }
static void timeout(int x) { errno = x = ETIMEDOUT; die_fatal("closing connection", 0, 0); }
void die_badmessage(void) { errno = EPROTO; die_fatal("unable to read from file descriptor 8",0,0); }
static void flush(void) { if (writeall(1, buf, buflen) == -1) die_fatal("unable to write output", 0); buflen = 0; }
int main(int argc,char **argv) { long long hellopackets; long long r; long long nextaction; signal(SIGPIPE,SIG_IGN); if (!argv[0]) die_usage(0); for (;;) { char *x; if (!argv[1]) break; if (argv[1][0] != '-') break; x = *++argv; if (x[0] == '-' && x[1] == 0) break; if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; while (*++x) { if (*x == 'q') { flagverbose = 0; continue; } if (*x == 'Q') { flagverbose = 1; continue; } if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } if (*x == 'c') { if (x[1]) { keydir = x + 1; break; } if (argv[1]) { keydir = *++argv; break; } } die_usage(0); } } if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots"); if (!hexparse(serverlongtermpk,32,*++argv)) die_usage("pk must be exactly 64 hex characters"); if (!multiipparse(serverip,*++argv)) die_usage("ip must be a comma-separated series of IPv4 addresses"); if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535"); if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters"); if (!*++argv) die_usage("missing prog"); for (;;) { r = open_read("/dev/null"); if (r == -1) die_fatal("unable to open /dev/null",0,0); if (r > 9) { close(r); break; } } if (keydir) { fdwd = open_cwd(); if (fdwd == -1) die_fatal("unable to open current working directory",0,0); if (chdir(keydir) == -1) die_fatal("unable to change to directory",keydir,0); if (load("publickey",clientlongtermpk,sizeof clientlongtermpk) == -1) die_fatal("unable to read public key from",keydir,0); if (load(".expertsonly/secretkey",clientlongtermsk,sizeof clientlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0); } else { crypto_box_keypair(clientlongtermpk,clientlongtermsk); } crypto_box_keypair(clientshorttermpk,clientshorttermsk); clientshorttermnonce = randommod(281474976710656LL); crypto_box_beforenm(clientshortserverlong,serverlongtermpk,clientshorttermsk); crypto_box_beforenm(clientlongserverlong,serverlongtermpk,clientlongtermsk); udpfd = socket_udp(); if (udpfd == -1) die_fatal("unable to create socket",0,0); for (hellopackets = 0;hellopackets < NUMIP;++hellopackets) { recent = nanoseconds(); /* send a Hello packet: */ clientextension_init(); clientshorttermnonce_update(); byte_copy(nonce,16,"CurveCP-client-H"); uint64_pack(nonce + 16,clientshorttermnonce); byte_copy(packet,8,"QvnQ5XlH"); byte_copy(packet + 8,16,serverextension); byte_copy(packet + 24,16,clientextension); byte_copy(packet + 40,32,clientshorttermpk); byte_copy(packet + 72,64,allzero); byte_copy(packet + 136,8,nonce + 16); crypto_box_afternm(text,allzero,96,nonce,clientshortserverlong); byte_copy(packet + 144,80,text + 16); socket_send(udpfd,packet,224,serverip + 4 * hellopackets,serverport); nextaction = recent + hellowait[hellopackets] + randommod(hellowait[hellopackets]); for (;;) { long long timeout = nextaction - recent; if (timeout <= 0) break; p[0].fd = udpfd; p[0].events = POLLIN; if (poll(p,1,timeout / 1000000 + 1) < 0) p[0].revents = 0; do { /* try receiving a Cookie packet: */ if (!p[0].revents) break; r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport); if (r != 200) break; if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) & byte_isequal(packetport,2,serverport) & byte_isequal(packet,8,"RL3aNMXK") & byte_isequal(packet + 8,16,clientextension) & byte_isequal(packet + 24,16,serverextension) )) break; byte_copy(nonce,8,"CurveCPK"); byte_copy(nonce + 8,16,packet + 40); byte_zero(text,16); byte_copy(text + 16,144,packet + 56); if (crypto_box_open_afternm(text,text,160,nonce,clientshortserverlong)) break; byte_copy(servershorttermpk,32,text + 32); byte_copy(servercookie,96,text + 64); byte_copy(serverip,4,serverip + 4 * hellopackets); goto receivedcookie; } while (0); recent = nanoseconds(); } } errno = ETIMEDOUT; die_fatal("no response from server",0,0); receivedcookie: crypto_box_beforenm(clientshortservershort,servershorttermpk,clientshorttermsk); byte_copy(nonce,8,"CurveCPV"); if (keydir) { if (safenonce(nonce + 8,0) == -1) die_fatal("nonce-generation disaster",0,0); } else { randombytes(nonce + 8,16); } byte_zero(text,32); byte_copy(text + 32,32,clientshorttermpk); crypto_box_afternm(text,text,64,nonce,clientlongserverlong); byte_copy(vouch,16,nonce + 8); byte_copy(vouch + 16,48,text + 16); /* server is responding, so start child: */ if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0); if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0); child = fork(); if (child == -1) die_fatal("unable to fork",0,0); if (child == 0) { if (keydir) if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0); close(8); if (dup(tochild[0]) != 8) die_fatal("unable to dup",0,0); close(9); if (dup(fromchild[1]) != 9) die_fatal("unable to dup",0,0); /* XXX: set up environment variables */ signal(SIGPIPE,SIG_DFL); execvp(*argv,argv); die_fatal("unable to run",*argv,0); } close(fromchild[1]); close(tochild[0]); for (;;) { p[0].fd = udpfd; p[0].events = POLLIN; p[1].fd = fromchild[0]; p[1].events = POLLIN; if (poll(p,2,-1) < 0) { p[0].revents = 0; p[1].revents = 0; } do { /* try receiving a Message packet: */ if (!p[0].revents) break; r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport); if (r < 80) break; if (r > 1152) break; if (r & 15) break; packetnonce = uint64_unpack(packet + 40); if (flagreceivedmessage && packetnonce <= receivednonce) break; if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) & byte_isequal(packetport,2,serverport) & byte_isequal(packet,8,"RL3aNMXM") & byte_isequal(packet + 8,16,clientextension) & byte_isequal(packet + 24,16,serverextension) )) break; byte_copy(nonce,16,"CurveCP-server-M"); byte_copy(nonce + 16,8,packet + 40); byte_zero(text,16); byte_copy(text + 16,r - 48,packet + 48); if (crypto_box_open_afternm(text,text,r - 32,nonce,clientshortservershort)) break; if (!flagreceivedmessage) { flagreceivedmessage = 1; randombytes(clientlongtermpk,sizeof clientlongtermpk); randombytes(vouch,sizeof vouch); randombytes(servername,sizeof servername); randombytes(servercookie,sizeof servercookie); } receivednonce = packetnonce; text[31] = (r - 64) >> 4; /* child is responsible for reading all data immediately, so we won't block: */ if (writeall(tochild[1],text + 31,r - 63) == -1) goto done; } while (0); do { /* try receiving data from child: */ long long i; if (!p[1].revents) break; r = read(fromchild[0],childbuf,sizeof childbuf); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r <= 0) goto done; childbuflen = r; for (i = 0;i < childbuflen;++i) { if (childmessagelen < 0) goto done; if (childmessagelen >= sizeof childmessage) goto done; childmessage[childmessagelen++] = childbuf[i]; if (childmessage[0] & 128) goto done; if (childmessagelen == 1 + 16 * (unsigned long long) childmessage[0]) { clientextension_init(); clientshorttermnonce_update(); uint64_pack(nonce + 16,clientshorttermnonce); if (flagreceivedmessage) { r = childmessagelen - 1; if (r < 16) goto done; if (r > 1088) goto done; byte_copy(nonce,16,"CurveCP-client-M"); byte_zero(text,32); byte_copy(text + 32,r,childmessage + 1); crypto_box_afternm(text,text,r + 32,nonce,clientshortservershort); byte_copy(packet,8,"QvnQ5XlM"); byte_copy(packet + 8,16,serverextension); byte_copy(packet + 24,16,clientextension); byte_copy(packet + 40,32,clientshorttermpk); byte_copy(packet + 72,8,nonce + 16); byte_copy(packet + 80,r + 16,text + 16); socket_send(udpfd,packet,r + 96,serverip,serverport); } else { r = childmessagelen - 1; if (r < 16) goto done; if (r > 640) goto done; byte_copy(nonce,16,"CurveCP-client-I"); byte_zero(text,32); byte_copy(text + 32,32,clientlongtermpk); byte_copy(text + 64,64,vouch); byte_copy(text + 128,256,servername); byte_copy(text + 384,r,childmessage + 1); crypto_box_afternm(text,text,r + 384,nonce,clientshortservershort); byte_copy(packet,8,"QvnQ5XlI"); byte_copy(packet + 8,16,serverextension); byte_copy(packet + 24,16,clientextension); byte_copy(packet + 40,32,clientshorttermpk); byte_copy(packet + 72,96,servercookie); byte_copy(packet + 168,8,nonce + 16); byte_copy(packet + 176,r + 368,text + 16); socket_send(udpfd,packet,r + 544,serverip,serverport); } childmessagelen = 0; } } } while (0); } done: do { r = waitpid(child,&childstatus,0); } while (r == -1 && errno == EINTR); if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } return WEXITSTATUS(childstatus); }
int main(int argc,char **argv) { long long pos; long long len; long long u; long long r; long long i; long long k; long long recent; long long nextaction; long long timeout; struct pollfd *q; struct pollfd *watch8; struct pollfd *watchtochild; struct pollfd *watchfromchild; signal(SIGPIPE,SIG_IGN); if (!argv[0]) die_usage(0); for (;;) { char *x; if (!argv[1]) break; if (argv[1][0] != '-') break; x = *++argv; if (x[0] == '-' && x[1] == 0) break; if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; while (*++x) { if (*x == 'q') { flagverbose = 0; continue; } if (*x == 'Q') { flagverbose = 1; continue; } if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } if (*x == 'c') { flagserver = 0; wantping = 2; continue; } if (*x == 'C') { flagserver = 0; wantping = 1; continue; } if (*x == 's') { flagserver = 1; wantping = 0; continue; } die_usage(0); } } if (!*++argv) die_usage("missing prog"); for (;;) { r = open_read("/dev/null"); if (r == -1) die_fatal("unable to open /dev/null",0,0); if (r > 9) { close(r); break; } } if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0); if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0); blocking_enable(tochild[0]); blocking_enable(fromchild[1]); child = fork(); if (child == -1) die_fatal("unable to fork",0,0); if (child == 0) { close(8); close(9); if (flagserver) { close(0); if (dup(tochild[0]) != 0) die_fatal("unable to dup",0,0); close(1); if (dup(fromchild[1]) != 1) die_fatal("unable to dup",0,0); } else { close(6); if (dup(tochild[0]) != 6) die_fatal("unable to dup",0,0); close(7); if (dup(fromchild[1]) != 7) die_fatal("unable to dup",0,0); } signal(SIGPIPE,SIG_DFL); execvp(*argv,argv); die_fatal("unable to run",*argv,0); } close(tochild[0]); close(fromchild[1]); recent = nanoseconds(); lastspeedadjustment = recent; if (flagserver) maxblocklen = 1024; for (;;) { if (sendeofacked) if (receivewritten == receivetotalbytes) if (receiveeof) if (tochild[1] < 0) break; /* XXX: to re-ack should enter a TIME-WAIT state here */ q = p; watch8 = q; if (watch8) { q->fd = 8; q->events = POLLIN; ++q; } watchtochild = q; if (tochild[1] < 0) watchtochild = 0; if (receivewritten >= receivebytes) watchtochild = 0; if (watchtochild) { q->fd = tochild[1]; q->events = POLLOUT; ++q; } watchfromchild = q; if (sendeof) watchfromchild = 0; if (sendbytes + 4096 > sizeof sendbuf) watchfromchild = 0; if (watchfromchild) { q->fd = fromchild[0]; q->events = POLLIN; ++q; } nextaction = recent + 60000000000LL; if (wantping == 1) nextaction = recent + 1000000000; if (wantping == 2) nextaction = 0; if (blocknum < OUTGOING) if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes)) if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; if (earliestblocktime) { long long nextretry = earliestblocktime + rtt_timeout; if (nextretry < lastblocktime + nsecperblock) nextretry = lastblocktime + nsecperblock; if (nextretry < nextaction) nextaction = nextretry; } if (messagenum) if (!watchtochild) nextaction = 0; if (nextaction <= recent) timeout = 0; else timeout = (nextaction - recent) / 1000000 + 1; /* XXX */ if (childdied) timeout = 10; pollret = poll(p,q - p,timeout); if (pollret < 0) { watch8 = 0; watchtochild = 0; watchfromchild = 0; } else { if (watch8) if (!watch8->revents) watch8 = 0; if (watchtochild) if (!watchtochild->revents) watchtochild = 0; if (watchfromchild) if (!watchfromchild->revents) watchfromchild = 0; } /* XXX */ if (childdied && !pollret) { if (childdied++ > 999) goto finish; } /* XXX: keepalives */ do { /* try receiving data from child: */ if (!watchfromchild) break; if (sendeof) break; if (sendbytes + 4096 > sizeof sendbuf) break; pos = (sendacked & (sizeof sendbuf - 1)) + sendbytes; if (pos < sizeof sendbuf) { r = read(fromchild[0],sendbuf + pos,sizeof sendbuf - pos); } else { r = read(fromchild[0],sendbuf + pos - sizeof sendbuf,sizeof sendbuf - sendbytes); } if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r < 0) { sendeof = 4096; break; } if (r == 0) { sendeof = 2048; break; } sendbytes += r; if (sendbytes >= 1152921504606846976LL) die_internalerror(); } while(0); recent = nanoseconds(); do { /* try re-sending an old block: */ if (recent < lastblocktime + nsecperblock) break; if (earliestblocktime == 0) break; if (recent < earliestblocktime + rtt_timeout) break; for (i = 0;i < blocknum;++i) { pos = (blockfirst + i) & (OUTGOING - 1); if (blocktime[pos] == earliestblocktime) { if (recent > lastpanic + 4 * rtt_timeout) { nsecperblock *= 2; lastpanic = recent; lastedge = recent; } goto sendblock; } } } while(0); do { /* try sending a new block: */ if (recent < lastblocktime + nsecperblock) break; if (blocknum >= OUTGOING) break; if (!wantping) if (sendeof ? sendeofprocessed : sendprocessed >= sendbytes) break; /* XXX: if any Nagle-type processing is desired, do it here */ pos = (blockfirst + blocknum) & (OUTGOING - 1); ++blocknum; blockpos[pos] = sendacked + sendprocessed; blocklen[pos] = sendbytes - sendprocessed; if (blocklen[pos] > maxblocklen) blocklen[pos] = maxblocklen; if ((blockpos[pos] & (sizeof sendbuf - 1)) + blocklen[pos] > sizeof sendbuf) blocklen[pos] = sizeof sendbuf - (blockpos[pos] & (sizeof sendbuf - 1)); /* XXX: or could have the full block in post-buffer space */ sendprocessed += blocklen[pos]; blockeof[pos] = 0; if (sendprocessed == sendbytes) { blockeof[pos] = sendeof; if (sendeof) sendeofprocessed = 1; } blocktransmissions[pos] = 0; sendblock: blocktransmissions[pos] += 1; blocktime[pos] = recent; blockid[pos] = nextmessageid; if (!++nextmessageid) ++nextmessageid; /* constraints: u multiple of 16; u >= 16; u <= 1088; u >= 48 + blocklen[pos] */ u = 64 + blocklen[pos]; if (u <= 192) u = 192; else if (u <= 320) u = 320; else if (u <= 576) u = 576; else if (u <= 1088) u = 1088; else die_internalerror(); if (blocklen[pos] < 0 || blocklen[pos] > 1024) die_internalerror(); byte_zero(buf + 8,u); buf[7] = u / 16; uint32_pack(buf + 8,blockid[pos]); /* XXX: include any acknowledgments that have piled up */ uint16_pack(buf + 46,blockeof[pos] | (crypto_uint16) blocklen[pos]); uint64_pack(buf + 48,blockpos[pos]); byte_copy(buf + 8 + u - blocklen[pos],blocklen[pos],sendbuf + (blockpos[pos] & (sizeof sendbuf - 1))); if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); lastblocktime = recent; wantping = 0; earliestblocktime_compute(); } while(0); do { /* try receiving messages: */ if (!watch8) break; r = read(8,buf,sizeof buf); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r == 0) die_badmessage(); if (r < 0) die_fatal("unable to read from file descriptor 8",0,0); for (k = 0;k < r;++k) { messagetodo[messagetodolen++] = buf[k]; u = 16 * (unsigned long long) messagetodo[0]; if (u < 16) die_badmessage(); if (u > 1088) die_badmessage(); if (messagetodolen == 1 + u) { if (messagenum < INCOMING) { pos = (messagefirst + messagenum) & (INCOMING - 1); messagelen[pos] = messagetodo[0]; byte_copy(message[pos],u,messagetodo + 1); ++messagenum; } else { ; /* drop tail */ } messagetodolen = 0; } } } while(0); do { /* try processing a message: */ if (!messagenum) break; if (tochild[1] >= 0 && receivewritten < receivebytes) break; maxblocklen = 1024; pos = messagefirst & (INCOMING - 1); len = 16 * (unsigned long long) messagelen[pos]; do { /* handle this message if it's comprehensible: */ unsigned long long D; unsigned long long SF; unsigned long long startbyte; unsigned long long stopbyte; crypto_uint32 id; long long i; if (len < 48) break; if (len > 1088) break; id = uint32_unpack(message[pos] + 4); for (i = 0;i < blocknum;++i) { k = (blockfirst + i) & (OUTGOING - 1); if (blockid[k] == id) { rtt = recent - blocktime[k]; if (!rtt_average) { nsecperblock = rtt; rtt_average = rtt; rtt_deviation = rtt / 2; rtt_highwater = rtt; rtt_lowwater = rtt; } /* Jacobson's retransmission timeout calculation: */ rtt_delta = rtt - rtt_average; rtt_average += rtt_delta / 8; if (rtt_delta < 0) rtt_delta = -rtt_delta; rtt_delta -= rtt_deviation; rtt_deviation += rtt_delta / 4; rtt_timeout = rtt_average + 4 * rtt_deviation; /* adjust for delayed acks with anti-spiking: */ rtt_timeout += 8 * nsecperblock; /* recognizing top and bottom of congestion cycle: */ rtt_delta = rtt - rtt_highwater; rtt_highwater += rtt_delta / 1024; rtt_delta = rtt - rtt_lowwater; if (rtt_delta > 0) rtt_lowwater += rtt_delta / 8192; else rtt_lowwater += rtt_delta / 256; if (rtt_average > rtt_highwater + 5000000) rtt_seenrecenthigh = 1; else if (rtt_average < rtt_lowwater) rtt_seenrecentlow = 1; if (recent >= lastspeedadjustment + 16 * nsecperblock) { if (recent - lastspeedadjustment > 10000000000LL) { nsecperblock = 1000000000; /* slow restart */ nsecperblock += randommod(nsecperblock / 8); } lastspeedadjustment = recent; if (nsecperblock >= 131072) { /* additive increase: adjust 1/N by a constant c */ /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */ /* approximation: adjust 1/N by cN every N nanoseconds */ /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */ if (nsecperblock < 16777216) { /* N/(1+cN^2) approx N - cN^3 */ u = nsecperblock / 131072; nsecperblock -= u * u * u; } else { double d = nsecperblock; nsecperblock = d/(1 + d*d / 2251799813685248.0); } } if (rtt_phase == 0) { if (rtt_seenolderhigh) { rtt_phase = 1; lastedge = recent; nsecperblock += randommod(nsecperblock / 4); } } else { if (rtt_seenolderlow) { rtt_phase = 0; } } rtt_seenolderhigh = rtt_seenrecenthigh; rtt_seenolderlow = rtt_seenrecentlow; rtt_seenrecenthigh = 0; rtt_seenrecentlow = 0; } do { if (recent - lastedge < 60000000000LL) { if (recent < lastdoubling + 4 * nsecperblock + 64 * rtt_timeout + 5000000000LL) break; } else { if (recent < lastdoubling + 4 * nsecperblock + 2 * rtt_timeout) break; } if (nsecperblock <= 65535) break; nsecperblock /= 2; lastdoubling = recent; if (lastedge) lastedge = recent; } while(0); } } stopbyte = uint64_unpack(message[pos] + 8); acknowledged(0,stopbyte); startbyte = stopbyte + (unsigned long long) uint32_unpack(message[pos] + 16); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 20); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 22); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 24); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 26); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 28); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 30); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 32); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 34); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 36); acknowledged(startbyte,stopbyte); D = uint16_unpack(message[pos] + 38); SF = D & (2048 + 4096); D -= SF; if (D > 1024) break; if (48 + D > len) break; startbyte = uint64_unpack(message[pos] + 40); stopbyte = startbyte + D; if (stopbyte > receivewritten + sizeof receivebuf) { break; /* of course, flow control would avoid this case */ } if (SF) { receiveeof = SF; receivetotalbytes = stopbyte; } for (k = 0;k < D;++k) { unsigned char ch = message[pos][len - D + k]; unsigned long long where = startbyte + k; if (where >= receivewritten && where < receivewritten + sizeof receivebuf) { receivevalid[where & (sizeof receivebuf - 1)] = 1; receivebuf[where & (sizeof receivebuf - 1)] = ch; } } for (;;) { if (receivebytes >= receivewritten + sizeof receivebuf) break; if (!receivevalid[receivebytes & (sizeof receivebuf - 1)]) break; ++receivebytes; } if (!uint32_unpack(message[pos])) break; /* never acknowledge a pure acknowledgment */ /* XXX: delay acknowledgments */ u = 192; byte_zero(buf + 8,u); buf[7] = u / 16; byte_copy(buf + 12,4,message[pos]); if (receiveeof && receivebytes == receivetotalbytes) { uint64_pack(buf + 16,receivebytes + 1); } else uint64_pack(buf + 16,receivebytes); /* XXX: incorporate selective acknowledgments */ if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); } while(0); ++messagefirst; --messagenum; } while(0); do { /* try sending data to child: */ if (!watchtochild) break; if (tochild[1] < 0) { receivewritten = receivebytes; break; } if (receivewritten >= receivebytes) break; pos = receivewritten & (sizeof receivebuf - 1); len = receivebytes - receivewritten; if (pos + len > sizeof receivebuf) len = sizeof receivebuf - pos; r = write(tochild[1],receivebuf + pos,len); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r <= 0) { close(tochild[1]); tochild[1] = -1; break; } byte_zero(receivevalid + pos,r); receivewritten += r; } while(0); do { /* try closing pipe to child: */ if (!receiveeof) break; if (receivewritten < receivetotalbytes) break; if (tochild[1] < 0) break; if (receiveeof == 4096) ; /* XXX: UNIX doesn't provide a way to signal an error through a pipe */ close(tochild[1]); tochild[1] = -1; } while(0); /* XXX */ if (!childdied){ if (waitpid(child,&childstatus, WNOHANG) > 0) { close(tochild[1]); tochild[1] = -1; childdied = 1; } } } if (!childdied) { do { r = waitpid(child,&childstatus,0); } while (r == -1 && errno == EINTR); } finish: if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } return WEXITSTATUS(childstatus); }
void create(const char *d,const char *fn,const unsigned char *x,long long xlen) { if (savesync(fn,x,xlen) == -1) die_fatal("unable to create",d,fn); }
void die_internalerror(void) { errno = EPROTO; die_fatal("internal error",0,0); }
int main(int argc, char **argv) { unsigned char *x; unsigned long long xlen; if (argv[0]) if (argv[1]) { if (str_equal(argv[1], "-h")) die_usage(0); } /* get password */ x = (unsigned char *)env_get("PASSWORD"); if (!x) { errno = 0; die_usage("$PASSWORD not set"); } xlen = str_len((char *)x); /* create salt */ randombytes(s, sizeof s); /* derive key */ if (sha512hmacpbkdf2(h, sizeof h, x, xlen, s, sizeof s, ROUNDS) == -1) die_fatal("unable to derive keys", 0); byte_zero(x, xlen); /* create nonce */ randombytes(n, sizeof n); uint64_pack(n, nanoseconds()); sha512(nk, (unsigned char *)MAGIC, MAGICBYTES); crypto_block_aes256vulnerable(n, n, nk); /* initialize */ crypto_init(&ctx, n, h, MAGIC); randombytes(h, sizeof h); sha512_init(&shactx); /* write header */ if (writeall(1, MAGIC, MAGICBYTES) == -1) die_fatal("unable to write output", 0); if (writeall(1, s, sizeof s) == -1) die_fatal("unable to write output", 0); randombytes(s, sizeof s); if (writeall(1, n, sizeof n) == -1) die_fatal("unable to write output", 0); for (;;) { inlen = readblock(in, BLOCK); if (inlen != BLOCK) break; if (sha512_block(&shactx, in, inlen) != 0) die_fatal("unable to compute hash", 0); if (crypto_block(&ctx, in, inlen) != 0) die_fatal("unable to encrypt stream", 0); if (writeall(1, in, inlen) == -1) die_fatal("unable to write output", 0); } if (sha512_last(&shactx, h, in, inlen) != 0) die_fatal("unable to compute hash", 0); byte_copy(in + inlen, CHECKSUMBYTES, h); inlen += CHECKSUMBYTES; if (crypto_last(&ctx, in, inlen) != 0) die_fatal("unable to encrypt stream", 0); if (writeall(1, in, inlen) == -1) die_fatal("unable to write output", 0); if (fsyncfd(1) == -1) die_fatal("unable to write output", 0); cleanup(); _exit(0); }