/* * Copyright (c) 2000, 2004 Niels Provos * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Copyright (c) 1997 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "config.h" #include #include #include #ifdef HAVE_LIBEDIT #include #endif #include #include #include #include #include #include #include #ifdef HAVE_LIBREADLINE #include #include #endif #if !defined(HAVE_LIBEDIT) && !defined(HAVE_LIBREADLINE) #error "Need either libedit or libreadline" #endif #define LINELEN 2048 char Buffer[LINELEN]; #define CTLNAME "honeydctl" #define HONEYD_SOCK "/var/run/honeyd.sock" int usage() { fprintf(stderr, "usage: %s [-v] [-t n] [LocalSock]\n" "\t -v tells %s to output all conversation\n" "\t -t n specifies a timeout of n seconds when connecting\n", CTLNAME, CTLNAME); exit(1); } int TimedOut = 0; void Timeout(int Sig) { TimedOut = 1; } #define REC_SHOW (2) #define REC_VERBOSE (4) char *passwd; char *prompt; #ifdef HAVE_LIBEDIT char * getprompt(EditLine *e) { if (prompt == NULL) prompt = ""; return prompt; } #endif int receive(int fd, int display) { int Result; int len; char *last; prompt = Buffer; len = 0; while (Result = read(fd, Buffer+len, sizeof(Buffer)-len-1), Result != -1) { if (Result == 0 && errno != EINTR) { Result = -1; break; } len += Result; Buffer[len] = '\0'; if (len > 2 && !strcmp(Buffer+len-2, "> ")) { prompt = strrchr(Buffer, '\n'); if (display & (REC_SHOW|REC_VERBOSE)) { if (display & REC_VERBOSE) last = Buffer+len-1; else last = prompt; if (last) { last++; write(1, Buffer, last-Buffer); } } prompt = prompt == NULL ? Buffer : prompt+1; for (last = Buffer+len-2; last > Buffer && *last != ' '; last--) ; if (last > Buffer+3 && !strncmp(last-3, " on", 3)) { /* a password is required ! */ Result = 1; } else Result = 0; break; } if (len == sizeof (Buffer) - 1) { int flush; if ((last = strrchr(Buffer, '\n')) == NULL) /* Yeuch - this is one mother of a line ! */ flush = sizeof (Buffer) / 2; else flush = last - Buffer + 1; write(1, Buffer, flush); strlcpy(Buffer, Buffer + flush, sizeof(Buffer)); len -= flush; } } return Result; } int data = -1; jmp_buf pppdead; void check_fd(int sig) { if (data != -1) { struct timeval t; fd_set f; static char buf[LINELEN]; int len; FD_ZERO(&f); FD_SET(data, &f); t.tv_sec = t.tv_usec = 0; if (select(data+1, &f, NULL, NULL, &t) > 0) { len = read(data, buf, sizeof (buf)); if (len > 0) write(fileno(stdout), buf, len); else longjmp(pppdead, -1); } } } const char * #ifdef HAVE_LIBEDIT smartgets(EditLine *e, int *count, int fd) #else smartgets(int *count, int fd) #endif { const char *result; data = fd; signal(SIGALRM, check_fd); ualarm(500000, 500000); result = setjmp(pppdead) ? NULL : #ifdef HAVE_LIBEDIT el_gets(e, count); #else readline(prompt); if (result != NULL) *count = strlen(result); #endif ualarm(0,0); signal(SIGALRM, SIG_DFL); data = -1; return result; } int main(int argc, char **argv) { struct sockaddr *sock; struct sockaddr_un ifsun; int fd, len, verbose, save_errno; unsigned TimeoutVal; struct sigaction act, oact; char *sockname = HONEYD_SOCK; #ifdef HAVE_LIBEDIT EditLine *edit; History *hist; HistEvent hev = { 0, "" }; #endif const char *l; int ch; verbose = 0; TimeoutVal = 2; while ((ch = getopt(argc, argv, "t:v")) != -1) { switch (ch) { case 't': TimeoutVal = (unsigned)atoi(optarg); break; case 'v': verbose = REC_VERBOSE; break; default: usage(); } } argc -= optind; argv += optind; if (argc > 0) sockname = argv[0]; sock = (struct sockaddr *)&ifsun; memset(&ifsun, '\0', sizeof (ifsun)); #ifdef HAVE_SUN_LEN ifsun.sun_len = strlen(sockname); if (ifsun.sun_len > sizeof (ifsun.sun_path) - 1) errx(1, "%s: path too long", sockname); #endif /* HAVE_SUN_LEN */ ifsun.sun_family = AF_UNIX; strlcpy(ifsun.sun_path, sockname, sizeof(ifsun.sun_path)); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) errx(2, "cannot create local domain socket"); TimedOut = 0; if (TimeoutVal) { act.sa_handler = Timeout; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM, &act, &oact); alarm(TimeoutVal); } if (connect(fd, sock, sizeof (ifsun)) == -1) { if (TimeoutVal) { save_errno = errno; alarm(0); sigaction(SIGALRM, &oact, 0); errno = save_errno; } if (TimedOut) warnx("timeout: cannot connect to socket %s", sockname); else warn("cannot connect to socket %s", sockname); close(fd); return 3; } if (TimeoutVal) { alarm(0); sigaction(SIGALRM, &oact, 0); } /* Get Prompt ? */ receive(fd, REC_SHOW); #ifdef HAVE_LIBEDIT hist = history_init(); # ifdef H_SETSIZE history(hist, &hev, H_SETSIZE, 20); edit = el_init("honeydctl", stdin, stdout, stderr); # else /* !H_SETSIZE */ history(hist, H_EVENT, 20); edit = el_init("honeydctl", stdin, stdout); # endif el_source(edit, NULL); el_set(edit, EL_PROMPT, getprompt); el_set(edit, EL_EDITOR, "emacs"); el_set(edit, EL_SIGNAL, 1); el_set(edit, EL_HIST, history, (const char *)hist); #endif #ifdef HAVE_LIBEDIT while ((l = smartgets(edit, &len, fd))) { if (len > 1) # ifdef H_SETSIZE history(hist, &hev, H_ENTER, l); # else history(hist, H_ENTER, l); # endif /* H_SETSIZE */ #else /* !HAVE_LIBEDIT */ while ((l = smartgets(&len, fd))) { char line[128]; if (len > 0) { add_history((char *)l); snprintf(line, sizeof(line), "%s\n", l); l = line; len++; } #endif write(fd, l, len); if (receive(fd, REC_SHOW) != 0) break; } fprintf(stderr, "Connection closed\n"); #ifdef HAVE_LIBEDIT el_end(edit); history_end(hist); #endif close(fd); return 0; }