/* Prints up to 16 characters in hexdump style with optional colors * if `ascii' is non-zero, an additional ascii representation is printed */ void hexdump_line(int fd, const void *data, ssize_t len, int offset, int ascii, const char *description, const unsigned char *indices, const char *colors[]) { int i, cur = -1; char c; if ( description != NULL ) fd_printf(fd, " %s%s%s\n", desc_color, description, reset); for (i=0; i<16; i++) { if (i == 0) { if (offset) fd_printf(fd, "%08x ", data); else fd_printf(fd, " "); } else if (i % 8 == 0) fd_printf(fd, " "); if (i < len) { if ( indices && colors && (cur != indices[i]) ) fd_printf(fd, "%s", colors[cur = indices[i]]); fd_printf(fd, " %02x", ((const unsigned char *)data)[i]); } else fd_printf(fd, " "); } if (indices && colors) fd_printf(fd, "\033[m"); if (ascii && len > 0) { cur = -1; fd_printf(fd, " |"); for (i=0; i<16; i++) { if (i == len) break; if ( indices && colors && (cur != indices[i]) ) fd_printf(fd, "%s", colors[cur = indices[i]]); c = ((const unsigned char *)data)[i]; fd_printf(fd, "%c", isprint(c)?c:'.'); } if (indices && colors) fd_printf(fd, "\033[m"); fd_printf(fd, "|"); } fd_printf(fd, "\n"); }
/* Read a character (until one is available) and store it in buffer */ static void vtty_read_and_store(vtty_t *vtty,int *fd_slot) { int c; /* wait until we get a character input */ c = vtty_read(vtty,fd_slot); /* if read error, do nothing */ if (c < 0) return; /* If something was read, make sure the handler is informed */ vtty->input_pending = TRUE; if (!vtty->terminal_support) { vtty_store(vtty,c); return; } switch(vtty->input_state) { case VTTY_INPUT_TEXT : switch(c) { case 0x1b: vtty->input_state = VTTY_INPUT_VT1; return; /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */ case 0x1d: case 0xb3: if (ctrl_code_ok == 1) { vtty->input_state = VTTY_INPUT_REMOTE; } else { vtty_store(vtty,c); } return; case IAC : vtty->input_state = VTTY_INPUT_TELNET; return; case 0: /* NULL - Must be ignored - generated by Linux telnet */ case 10: /* LF (Line Feed) - Must be ignored on Windows platform */ return; default: /* Store a standard character */ vtty_store(vtty,c); return; } case VTTY_INPUT_VT1 : switch(c) { case 0x5b: vtty->input_state = VTTY_INPUT_VT2; return; default: vtty_store(vtty,0x1b); vtty_store(vtty,c); } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_VT2 : switch(c) { case 0x41: /* Up Arrow */ vtty_store(vtty,16); break; case 0x42: /* Down Arrow */ vtty_store(vtty,14); break; case 0x43: /* Right Arrow */ vtty_store(vtty,6); break; case 0x44: /* Left Arrow */ vtty_store(vtty,2); break; default: vtty_store(vtty,0x5b); vtty_store(vtty,0x1b); vtty_store(vtty,c); break; } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_REMOTE : remote_control(vtty, c); vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET : vtty->telnet_cmd = c; switch(c) { case WILL: case WONT: case DO: case DONT: vtty->input_state = VTTY_INPUT_TELNET_IYOU; return; case SB : vtty->telnet_cmd = c; vtty->input_state = VTTY_INPUT_TELNET_SB1; return; case SE: break; case IAC : vtty_store(vtty, IAC); break; } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET_IYOU : vtty->telnet_opt = c; /* if telnet client can support ttype, ask it to send ttype string */ if ((vtty->telnet_cmd == WILL) && (vtty->telnet_opt == TELOPT_TTYPE)) { vtty_put_char(vtty, IAC); vtty_put_char(vtty, SB); vtty_put_char(vtty, TELOPT_TTYPE); vtty_put_char(vtty, TELQUAL_SEND); vtty_put_char(vtty, IAC); vtty_put_char(vtty, SE); } vtty->input_state = VTTY_INPUT_TEXT; return; case VTTY_INPUT_TELNET_SB1 : vtty->telnet_opt = c; vtty->input_state = VTTY_INPUT_TELNET_SB2; return; case VTTY_INPUT_TELNET_SB2 : vtty->telnet_qual = c; if ((vtty->telnet_opt == TELOPT_TTYPE) && (vtty->telnet_qual == TELQUAL_IS)) vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE; else vtty->input_state = VTTY_INPUT_TELNET_NEXT; return; case VTTY_INPUT_TELNET_SB_TTYPE : /* parse ttype string: first char is sufficient */ /* if client is xterm or vt, set the title bar */ if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) { fd_printf(*fd_slot,0,"\033]0;%s\07", vtty->vm->name); } vtty->input_state = VTTY_INPUT_TELNET_NEXT; return; case VTTY_INPUT_TELNET_NEXT : /* ignore all chars until next IAC */ if (c == IAC) vtty->input_state = VTTY_INPUT_TELNET; return; } }
int run_cmd(int fd, const char *cmd, const char *args_extra) { pid_t pid; sigset_t sigm, sigm_old; /* block signals, let child establish its own handlers */ sigemptyset(&sigm); sigaddset(&sigm, SIGTERM); sigprocmask(SIG_BLOCK, &sigm, &sigm_old); pid = fork(); if ( pid < 0 ) { sigprocmask(SIG_SETMASK, &sigm_old, NULL); fd_printf(STO, "*** cannot fork: %s ***\r\n", strerror(errno)); return -1; } else if ( pid ) { /* father: picocom */ int status, r; /* reset the mask */ sigprocmask(SIG_SETMASK, &sigm_old, NULL); /* wait for child to finish */ do { r = waitpid(pid, &status, 0); } while ( r < 0 && errno == EINTR ); /* reset terminal (back to raw mode) */ term_apply(STI, 0); /* check and report child return status */ if ( WIFEXITED(status) ) { fd_printf(STO, "\r\n*** exit status: %d ***\r\n", WEXITSTATUS(status)); return WEXITSTATUS(status); } else if ( WIFSIGNALED(status) ) { fd_printf(STO, "\r\n*** killed by signal: %d ***\r\n", WTERMSIG(status)); return -1; } else { fd_printf(STO, "\r\n*** abnormal termination: 0x%x ***\r\n", r); return -1; } } else { /* child: external program */ long fl; int argc; char *argv[RUNCMD_ARGS_MAX + 1]; int r; /* unmanage terminal, and reset it to canonical mode */ term_remove(STI); /* unmanage serial port fd, without reset */ term_erase(fd); /* set serial port fd to blocking mode */ fl = fcntl(fd, F_GETFL); fl &= ~O_NONBLOCK; fcntl(fd, F_SETFL, fl); /* connect stdin and stdout to serial port */ close(STI); close(STO); dup2(fd, STI); dup2(fd, STO); /* build command arguments vector */ argc = 0; r = split_quoted(cmd, &argc, argv, RUNCMD_ARGS_MAX); if ( r < 0 ) { fd_printf(STDERR_FILENO, "Cannot parse command\n"); exit(RUNCMD_EXEC_FAIL); } r = split_quoted(args_extra, &argc, argv, RUNCMD_ARGS_MAX); if ( r < 0 ) { fd_printf(STDERR_FILENO, "Cannot parse extra args\n"); exit(RUNCMD_EXEC_FAIL); } if ( argc < 1 ) { fd_printf(STDERR_FILENO, "No command given\n"); exit(RUNCMD_EXEC_FAIL); } argv[argc] = NULL; /* run extenral command */ fd_printf(STDERR_FILENO, "$ %s %s\n", cmd, args_extra); establish_child_signal_handlers(); sigprocmask(SIG_SETMASK, &sigm_old, NULL); execvp(argv[0], argv); fd_printf(STDERR_FILENO, "exec: %s\n", strerror(errno)); exit(RUNCMD_EXEC_FAIL); } }
/* Process command key. Returns non-zero if command results in picocom exit, zero otherwise. */ int do_command (unsigned char c) { static int dtr_up = 0; int newbaud, newflow, newparity, newbits, newstopbits; const char *xfr_cmd; char *fname; int r; switch (c) { case KEY_EXIT: return 1; case KEY_QUIT: term_set_hupcl(tty_fd, 0); term_flush(tty_fd); term_apply(tty_fd, 1); term_erase(tty_fd); return 1; case KEY_STATUS: show_status(dtr_up); break; case KEY_HELP: case KEY_KEYS: show_keys(); break; case KEY_PULSE: fd_printf(STO, "\r\n*** pulse DTR ***\r\n"); if ( term_pulse_dtr(tty_fd) < 0 ) fd_printf(STO, "*** FAILED\r\n"); break; case KEY_TOGGLE: if ( dtr_up ) r = term_lower_dtr(tty_fd); else r = term_raise_dtr(tty_fd); if ( r >= 0 ) dtr_up = ! dtr_up; fd_printf(STO, "\r\n*** DTR: %s ***\r\n", dtr_up ? "up" : "down"); break; case KEY_BAUD: case KEY_BAUD_UP: case KEY_BAUD_DN: if ( c== KEY_BAUD) { newbaud = read_baud(); if ( newbaud < 0 ) { fd_printf(STO, "*** cannot read baudrate ***\r\n"); break; } opts.baud = newbaud; } else if (c == KEY_BAUD_UP) { opts.baud = baud_up(opts.baud); } else { opts.baud = baud_down(opts.baud); } term_set_baudrate(tty_fd, opts.baud); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbaud = term_get_baudrate(tty_fd, NULL); if ( opts.baud != newbaud ) { fd_printf(STO, "\r\n*** baud: %d (%d) ***\r\n", opts.baud, newbaud); } else { fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud); } set_tty_write_sz(newbaud); break; case KEY_FLOW: opts.flow = flow_next(opts.flow); term_set_flowcntrl(tty_fd, opts.flow); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newflow = term_get_flowcntrl(tty_fd); if ( opts.flow != newflow ) { fd_printf(STO, "\r\n*** flow: %s (%s) ***\r\n", flow_str[opts.flow], flow_str[newflow]); } else { fd_printf(STO, "\r\n*** flow: %s ***\r\n", flow_str[opts.flow]); } break; case KEY_PARITY: opts.parity = parity_next(opts.parity); term_set_parity(tty_fd, opts.parity); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newparity = term_get_parity(tty_fd); if (opts.parity != newparity ) { fd_printf(STO, "\r\n*** parity: %s (%s) ***\r\n", parity_str[opts.parity], parity_str[newparity]); } else { fd_printf(STO, "\r\n*** parity: %s ***\r\n", parity_str[opts.parity]); } break; case KEY_BITS: opts.databits = bits_next(opts.databits); term_set_databits(tty_fd, opts.databits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbits = term_get_databits(tty_fd); if (opts.databits != newbits ) { fd_printf(STO, "\r\n*** databits: %d (%d) ***\r\n", opts.databits, newbits); } else { fd_printf(STO, "\r\n*** databits: %d ***\r\n", opts.databits); } break; case KEY_STOP: opts.stopbits = stopbits_next(opts.stopbits); term_set_stopbits(tty_fd, opts.stopbits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newstopbits = term_get_stopbits(tty_fd); if (opts.stopbits != newstopbits ) { fd_printf(STO, "\r\n*** stopbits: %d (%d) ***\r\n", opts.stopbits, newstopbits); } else { fd_printf(STO, "\r\n*** stopbits: %d ***\r\n", opts.stopbits); } break; case KEY_LECHO: opts.lecho = ! opts.lecho; fd_printf(STO, "\r\n*** local echo: %s ***\r\n", opts.lecho ? "yes" : "no"); break; case KEY_SEND: case KEY_RECEIVE: xfr_cmd = (c == KEY_SEND) ? opts.send_cmd : opts.receive_cmd; if ( xfr_cmd[0] == '\0' ) { fd_printf(STO, "\r\n*** command disabled ***\r\n"); break; } fname = read_filename(); if (fname == NULL) { fd_printf(STO, "*** cannot read filename ***\r\n"); break; } run_cmd(tty_fd, xfr_cmd, fname); free(fname); break; case KEY_BREAK: term_break(tty_fd); fd_printf(STO, "\r\n*** break sent ***\r\n"); break; default: break; } return 0; }
void show_status (int dtr_up) { int baud, bits, stopbits, mctl; enum flowcntrl_e flow; enum parity_e parity; term_refresh(tty_fd); baud = term_get_baudrate(tty_fd, NULL); flow = term_get_flowcntrl(tty_fd); parity = term_get_parity(tty_fd); bits = term_get_databits(tty_fd); stopbits = term_get_stopbits(tty_fd); fd_printf(STO, "\r\n"); if ( baud != opts.baud ) { fd_printf(STO, "*** baud: %d (%d)\r\n", opts.baud, baud); } else { fd_printf(STO, "*** baud: %d\r\n", opts.baud); } if ( flow != opts.flow ) { fd_printf(STO, "*** flow: %s (%s)\r\n", flow_str[opts.flow], flow_str[flow]); } else { fd_printf(STO, "*** flow: %s\r\n", flow_str[opts.flow]); } if ( parity != opts.parity ) { fd_printf(STO, "*** parity: %s (%s)\r\n", parity_str[opts.parity], parity_str[parity]); } else { fd_printf(STO, "*** parity: %s\r\n", parity_str[opts.parity]); } if ( bits != opts.databits ) { fd_printf(STO, "*** databits: %d (%d)\r\n", opts.databits, bits); } else { fd_printf(STO, "*** databits: %d\r\n", opts.databits); } if ( stopbits != opts.stopbits ) { fd_printf(STO, "*** stopbits: %d (%d)\r\n", opts.stopbits, stopbits); } else { fd_printf(STO, "*** stopbits: %d\r\n", opts.stopbits); } mctl = term_get_mctl(tty_fd); if (mctl >= 0 && mctl != MCTL_UNAVAIL) { if ( ((mctl & MCTL_DTR) ? 1 : 0) == dtr_up ) fd_printf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down"); else fd_printf(STO, "*** dtr: %s (%s)\r\n", dtr_up ? "up" : "down", (mctl & MCTL_DTR) ? "up" : "down"); fd_printf(STO, "*** mctl: "); fd_printf(STO, "DTR:%c DSR:%c DCD:%c RTS:%c CTS:%c RI:%c\r\n", (mctl & MCTL_DTR) ? '1' : '0', (mctl & MCTL_DSR) ? '1' : '0', (mctl & MCTL_DCD) ? '1' : '0', (mctl & MCTL_RTS) ? '1' : '0', (mctl & MCTL_CTS) ? '1' : '0', (mctl & MCTL_RI) ? '1' : '0'); } else { fd_printf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down"); } }
void show_keys() { #ifndef NO_HELP fd_printf(STO, "\r\n"); fd_printf(STO, "*** Picocom commands (all prefixed by [C-%c])\r\n", KEYC(opts.escape)); fd_printf(STO, "\r\n"); fd_printf(STO, "*** [C-%c] : Exit picocom\r\n", KEYC(KEY_EXIT)); fd_printf(STO, "*** [C-%c] : Exit without reseting serial port\r\n", KEYC(KEY_QUIT)); fd_printf(STO, "*** [C-%c] : Set baudrate\r\n", KEYC(KEY_BAUD)); fd_printf(STO, "*** [C-%c] : Increase baudrate (baud-up)\r\n", KEYC(KEY_BAUD_UP)); fd_printf(STO, "*** [C-%c] : Decrease baudrate (baud-down)\r\n", KEYC(KEY_BAUD_DN));; fd_printf(STO, "*** [C-%c] : Change number of databits\r\n", KEYC(KEY_BITS)); fd_printf(STO, "*** [C-%c] : Change number of stopbits\r\n", KEYC(KEY_STOP)); fd_printf(STO, "*** [C-%c] : Change flow-control mode\r\n", KEYC(KEY_FLOW)); fd_printf(STO, "*** [C-%c] : Change parity mode\r\n", KEYC(KEY_PARITY)); fd_printf(STO, "*** [C-%c] : Pulse DTR\r\n", KEYC(KEY_PULSE)); fd_printf(STO, "*** [C-%c] : Toggle DTR\r\n", KEYC(KEY_TOGGLE)); fd_printf(STO, "*** [C-%c] : Send break\r\n", KEYC(KEY_BREAK)); fd_printf(STO, "*** [C-%c] : Toggle local echo\r\n", KEYC(KEY_LECHO)); fd_printf(STO, "*** [C-%c] : Send file\r\n", KEYC(KEY_SEND)); fd_printf(STO, "*** [C-%c] : Receive file\r\n", KEYC(KEY_RECEIVE)); fd_printf(STO, "*** [C-%c] : Show port settings\r\n", KEYC(KEY_STATUS)); fd_printf(STO, "*** [C-%c] : Show this message\r\n", KEYC(KEY_HELP)); fd_printf(STO, "\r\n"); #else /* defined NO_HELP */ fd_printf(STO, "*** Help is disabled.\r\n"); #endif /* of NO_HELP */ }
void loop(void) { enum { ST_COMMAND, ST_TRANSPARENT } state; fd_set rdset, wrset; int r, n; unsigned char c; tty_q.len = 0; state = ST_TRANSPARENT; while ( ! sig_exit ) { FD_ZERO(&rdset); FD_ZERO(&wrset); FD_SET(STI, &rdset); FD_SET(tty_fd, &rdset); if ( tty_q.len ) FD_SET(tty_fd, &wrset); r = select(tty_fd + 1, &rdset, &wrset, NULL, NULL); if ( r < 0 ) { if ( errno == EINTR ) continue; else fatal("select failed: %d : %s", errno, strerror(errno)); } if ( FD_ISSET(STI, &rdset) ) { /* read from terminal */ do { n = read(STI, &c, 1); } while (n < 0 && errno == EINTR); if (n == 0) { fatal("stdin closed"); } else if (n < 0) { /* is this really necessary? better safe than sory! */ if ( errno != EAGAIN && errno != EWOULDBLOCK ) fatal("read from stdin failed: %s", strerror(errno)); else goto skip_proc_STI; } switch (state) { case ST_COMMAND: if ( c == opts.escape ) { /* pass the escape character down */ if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) { n = do_map((char *)tty_q.buff + tty_q.len, opts.omap, c); tty_q.len += n; if ( opts.lecho ) map_and_write(STO, opts.emap, c); } else { fd_printf(STO, "\x07"); } } else { /* process command key */ if ( do_command(c) ) /* picocom exit */ return; } state = ST_TRANSPARENT; break; case ST_TRANSPARENT: if ( c == opts.escape ) { state = ST_COMMAND; } else { if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) { n = do_map((char *)tty_q.buff + tty_q.len, opts.omap, c); tty_q.len += n; if ( opts.lecho ) map_and_write(STO, opts.emap, c); } else fd_printf(STO, "\x07"); } break; default: assert(0); break; } } skip_proc_STI: if ( FD_ISSET(tty_fd, &rdset) ) { char buff_rd[TTY_RD_SZ]; char buff_map[TTY_RD_SZ * M_MAXMAP]; /* read from port */ do { n = read(tty_fd, &buff_rd, sizeof(buff_rd)); } while (n < 0 && errno == EINTR); if (n == 0) { fatal("term closed"); } else if ( n < 0 ) { if ( errno != EAGAIN && errno != EWOULDBLOCK ) fatal("read from term failed: %s", strerror(errno)); } else { int i; char *bmp = &buff_map[0]; for (i = 0; i < n; i++) { bmp += do_map(bmp, opts.imap, buff_rd[i]); } n = bmp - buff_map; if ( writen_ni(STO, buff_map, n) < n ) fatal("write to stdout failed: %s", strerror(errno)); } } if ( FD_ISSET(tty_fd, &wrset) ) { /* write to port */ int sz; sz = (tty_q.len < tty_write_sz) ? tty_q.len : tty_write_sz; do { n = write(tty_fd, tty_q.buff, sz); } while ( n < 0 && errno == EINTR ); if ( n <= 0 ) fatal("write to term failed: %s", strerror(errno)); memmove(tty_q.buff, tty_q.buff + n, tty_q.len - n); tty_q.len -= n; } } }
/** * Updates current->cols with the current window size (width), * and current->rows with the current window rows (height) */ static int getWindowSize(struct current *current) { struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) { current->cols = ws.ws_col; current->rows = ws.ws_row; return 0; } /* Failed to query the window size. Perhaps we are on a serial terminal. * Try to query the width by sending the cursor as far to the right * and reading back the cursor position. * Note that this is only done once per call to linenoise rather than * every time the line is refreshed for efficiency reasons. * * In more detail, we: * (a) request current cursor position, * (b) move cursor far right, far down * (c) request cursor position again, * (d) at last move back to the old position. * This gives us the width without messing with the externally * visible cursor position. * * Console codes: * A up * B down * C right * D left * * For portability we are NOT using the control sequences * ESC [ s * ESC [ u * to save and restore the cursor position, as many terminal * emulators do not honor them. */ if (current->cols == 0) { int herec; int herel; current->cols = 80; current->rows = 25; /* (a) */ if (queryCursor (current->fd, &herec, &herel)) { /* (b) */ fd_printf(current->fd, "\x1b[999C\x1b[999B"); /* (c). Note: If (a) succeeded, then (c) should as well. * For paranoia we still check and have a fallback action * for (d) in case of failure.. */ if (!queryCursor (current->fd, ¤t->cols, ¤t->rows)) { /* (d') Unable to get accurate position data, reset * the cursor to the far left. While this may not * restore the exact original position it should not * be too bad. We will have lost the vertical position * however. */ fd_printf(current->fd, "\r"); } else { /* (d) Reset the cursor back to the original location. */ if (current->cols > herec) { fd_printf(current->fd, "\x1b[%dD", current->cols - herec); } if (current->rows > herel) { fd_printf(current->fd, "\x1b[%dA", current->rows - herel); } } } /* 1st query failed, doing nothing => default 80 */ } return 0; }
static void eraseEol(struct current *current) { fd_printf(current->fd, "\x1b[0K"); }
static void setCursorPos(struct current *current, int x) { fd_printf(current->fd, "\r\x1b[%dC", x); }
static void outputControlChar(struct current *current, char ch) { fd_printf(current->fd, "\x1b[7m^%c\x1b[0m", ch); }
static void cursorToLeft(struct current *current) { fd_printf(current->fd, "\r"); }
static void clearScreen(struct current *current) { fd_printf(current->fd, "\x1b[H\x1b[2J"); }
NOEXPORT void imap_server(CLI *c) { char *line, *id, *tail, *capa; s_poll_init(c->fds); s_poll_add(c->fds, c->local_rfd.fd, 1, 0); switch(s_poll_wait(c->fds, 0, 200)) { case 0: /* fd not ready to read */ s_log(LOG_DEBUG, "RFC 2595 detected"); break; case 1: /* fd ready to read */ s_log(LOG_DEBUG, "RFC 2595 not detected"); return; /* return if RFC 2595 is not used */ default: /* -1 */ sockerror("RFC2595 (s_poll_wait)"); longjmp(c->err, 1); } /* process server welcome and send it to client */ line=fd_getline(c, c->remote_fd.fd); if(!is_prefix(line, "* OK")) { s_log(LOG_ERR, "Unknown server welcome"); str_free(line); longjmp(c->err, 1); } capa=strstr(line, "CAPABILITY"); if(!capa) capa=strstr(line, "capability"); if(capa) *capa='K'; /* disable CAPABILITY within greeting */ fd_printf(c, c->local_wfd.fd, "%s (stunnel)", line); id=str_dup(""); while(1) { /* process client commands */ str_free(line); line=fd_getline(c, c->local_rfd.fd); /* split line into id and tail */ str_free(id); id=str_dup(line); tail=strchr(id, ' '); if(!tail) break; *tail++='\0'; if(is_prefix(tail, "STARTTLS")) { fd_printf(c, c->local_wfd.fd, "%s OK Begin TLS negotiation now", id); str_free(line); str_free(id); return; /* success */ } else if(is_prefix(tail, "CAPABILITY")) { fd_putline(c, c->remote_fd.fd, line); /* send it to server */ str_free(line); line=fd_getline(c, c->remote_fd.fd); /* get the capabilites */ if(*line=='*') { /* * append STARTTLS * should also add LOGINDISABLED, but can't because * of Mozilla bug #324138/#312009 * LOGIN would fail as "unexpected command", anyway */ fd_printf(c, c->local_wfd.fd, "%s STARTTLS", line); str_free(line); line=fd_getline(c, c->remote_fd.fd); /* next line */ } fd_putline(c, c->local_wfd.fd, line); /* forward to the client */ tail=strchr(line, ' '); if(!tail || !is_prefix(tail+1, "OK")) { /* not OK? */ fd_putline(c, c->local_wfd.fd, "* BYE unexpected server response"); s_log(LOG_ERR, "Unexpected server response: %s", line); break; } } else if(is_prefix(tail, "LOGOUT")) { fd_putline(c, c->local_wfd.fd, "* BYE server terminating"); fd_printf(c, c->local_wfd.fd, "%s OK LOGOUT completed", id); break; } else { fd_putline(c, c->local_wfd.fd, "* BYE stunnel: unexpected command"); fd_printf(c, c->local_wfd.fd, "%s BAD %s unexpected", id, tail); s_log(LOG_ERR, "Unexpected client command %s", tail); break; } } /* clean server shutdown */ str_free(id); fd_putline(c, c->remote_fd.fd, "stunnel LOGOUT"); str_free(line); line=fd_getline(c, c->remote_fd.fd); if(*line=='*') { str_free(line); line=fd_getline(c, c->remote_fd.fd); } str_free(line); longjmp(c->err, 2); /* don't reset */ }
int main(int argc, char *argv[]) { int r; parse_args(argc, argv); establish_signal_handlers(); r = term_lib_init(); if ( r < 0 ) fatal("term_init failed: %s", term_strerror(term_errno, errno)); #ifdef UUCP_LOCK_DIR if ( ! opts.nolock ) uucp_lockname(UUCP_LOCK_DIR, opts.port); if ( uucp_lock() < 0 ) fatal("cannot lock %s: %s", opts.port, strerror(errno)); #endif tty_fd = open(opts.port, O_RDWR | O_NONBLOCK | O_NOCTTY); if (tty_fd < 0) fatal("cannot open %s: %s", opts.port, strerror(errno)); #ifdef USE_FLOCK if ( ! opts.nolock ) { r = flock(tty_fd, LOCK_EX | LOCK_NB); if ( r < 0 ) fatal("cannot lock %s: %s", opts.port, strerror(errno)); } #endif if ( opts.noinit ) { r = term_add(tty_fd); } else { r = term_set(tty_fd, 1, /* raw mode. */ opts.baud, /* baud rate. */ opts.parity, /* parity. */ opts.databits, /* data bits. */ opts.stopbits, /* stop bits. */ opts.flow, /* flow control. */ 1, /* local or modem */ !opts.noreset); /* hup-on-close. */ } if ( r < 0 ) fatal("failed to add device %s: %s", opts.port, term_strerror(term_errno, errno)); r = term_apply(tty_fd, 0); if ( r < 0 ) fatal("failed to config device %s: %s", opts.port, term_strerror(term_errno, errno)); set_tty_write_sz(term_get_baudrate(tty_fd, NULL)); r = term_add(STI); if ( r < 0 ) fatal("failed to add I/O device: %s", term_strerror(term_errno, errno)); term_set_raw(STI); r = term_apply(STI, 0); if ( r < 0 ) fatal("failed to set I/O device to raw mode: %s", term_strerror(term_errno, errno)); #ifdef LINENOISE init_history(); #endif #ifndef NO_HELP fd_printf(STO, "Type [C-%c] [C-%c] to see available commands\r\n\r\n", KEYC(opts.escape), KEYC(KEY_HELP)); #endif fd_printf(STO, "Terminal ready\r\n"); loop(); #ifdef LINENOISE cleanup_history(); #endif fd_printf(STO, "\r\n"); if ( opts.noreset ) { fd_printf(STO, "Skipping tty reset...\r\n"); term_erase(tty_fd); } if ( sig_exit ) fd_printf(STO, "Picocom was killed\r\n"); else fd_printf(STO, "Thanks for using picocom\r\n"); /* wait a bit for output to drain */ sleep(1); #ifdef UUCP_LOCK_DIR uucp_unlock(); #endif return EXIT_SUCCESS; }
NOEXPORT void ntlm(CLI *c) { char *line, buf[BUFSIZ], *ntlm1_txt, *ntlm2_txt, *ntlm3_txt, *tmpstr; long content_length=0; /* no HTTP content */ /* send Proxy-Authorization (phase 1) */ fd_printf(c, c->remote_fd.fd, "Proxy-Connection: keep-alive"); ntlm1_txt=ntlm1(); if(!ntlm1_txt) { s_log(LOG_ERR, "Proxy-Authenticate: Failed to build NTLM request"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "Proxy-Authorization: NTLM %s", ntlm1_txt); str_free(ntlm1_txt); fd_putline(c, c->remote_fd.fd, ""); /* empty line */ line=fd_getline(c, c->remote_fd.fd); /* receive Proxy-Authenticate (phase 2) */ if(!is_prefix(line, "HTTP/1.0 407") && !is_prefix(line, "HTTP/1.1 407")) { s_log(LOG_ERR, "Proxy-Authenticate: NTLM authorization request rejected"); do { /* read all headers */ str_free(line); line=fd_getline(c, c->remote_fd.fd); } while(*line); str_free(line); longjmp(c->err, 1); } ntlm2_txt=NULL; do { /* read all headers */ str_free(line); line=fd_getline(c, c->remote_fd.fd); if(is_prefix(line, "Proxy-Authenticate: NTLM ")) ntlm2_txt=str_dup(line+25); else if(is_prefix(line, "Content-Length: ")) { content_length=strtol(line+16, &tmpstr, 10); if(tmpstr==line+16 || *tmpstr || content_length<0) { s_log(LOG_ERR, "Proxy-Authenticate: Invalid Content-Length"); str_free(line); longjmp(c->err, 1); } } } while(*line); if(!ntlm2_txt) { /* no Proxy-Authenticate: NTLM header */ s_log(LOG_ERR, "Proxy-Authenticate: NTLM header not found"); str_free(line); longjmp(c->err, 1); } /* read and ignore HTTP content (if any) */ while(content_length>0) { s_read(c, c->remote_fd.fd, buf, s_min(content_length, BUFSIZ)); content_length-=s_min(content_length, BUFSIZ); } /* send Proxy-Authorization (phase 3) */ fd_printf(c, c->remote_fd.fd, "CONNECT %s HTTP/1.1", c->opt->protocol_host); fd_printf(c, c->remote_fd.fd, "Host: %s", c->opt->protocol_host); ntlm3_txt=ntlm3(c->opt->protocol_username, c->opt->protocol_password, ntlm2_txt); str_free(ntlm2_txt); if(!ntlm3_txt) { s_log(LOG_ERR, "Proxy-Authenticate: Failed to build NTLM response"); longjmp(c->err, 1); } fd_printf(c, c->remote_fd.fd, "Proxy-Authorization: NTLM %s", ntlm3_txt); str_free(ntlm3_txt); }
int write_section_header(int fd) { assert(fd>1 && "Invalid file descriptor"); fd_printf(fd, "%%%%\n"); // Just prints %% return 0; }