summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libipsecutil/Makefile.com4
-rw-r--r--usr/src/lib/libipsecutil/common/ipsec_util.c118
-rw-r--r--usr/src/lib/libipsecutil/common/ipsec_util.h12
3 files changed, 118 insertions, 16 deletions
diff --git a/usr/src/lib/libipsecutil/Makefile.com b/usr/src/lib/libipsecutil/Makefile.com
index fb3963e42f..9e14f96554 100644
--- a/usr/src/lib/libipsecutil/Makefile.com
+++ b/usr/src/lib/libipsecutil/Makefile.com
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -34,7 +34,7 @@ LIBS += $(DYNLIB) $(LINTLIB)
SRCDIR = ../common
$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
-LDLIBS += -lsocket -lnsl -lc
+LDLIBS += -ltecla -lsocket -lnsl -lc
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -I$(SRCDIR)
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.c b/usr/src/lib/libipsecutil/common/ipsec_util.c
index b64c240407..ade9d99e08 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.c
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -57,6 +57,10 @@
#define EFD(file) (((file) == stdout) ? stderr : (file))
+/* Limits for interactive mode. */
+#define MAX_LINE_LEN IBUF_SIZE
+#define MAX_CMD_HIST 64000 /* in bytes */
+
/* Set standard default/initial values for globals... */
boolean_t pflag = B_FALSE; /* paranoid w.r.t. printing keying material */
boolean_t nflag = B_FALSE; /* avoid nameservice? */
@@ -68,6 +72,7 @@ uint_t lines_parsed = 0;
jmp_buf env; /* for error recovery in interactive/readfile modes */
char *my_fmri = NULL;
FILE *debugfile = stderr;
+static GetLine *gl = NULL; /* for interactive mode */
/*
* Print errno and exit if cmdline or readfile, reset state if interactive
@@ -437,16 +442,97 @@ create_argv(char *ibuf, int *newargc, char ***thisargv)
}
/*
+ * init interactive mode if needed and not yet initialized
+ */
+static void
+init_interactive(FILE *infile, CplMatchFn *match_fn)
+{
+ if (infile == stdin) {
+ if (gl == NULL) {
+ if ((gl = new_GetLine(MAX_LINE_LEN,
+ MAX_CMD_HIST)) == NULL)
+ errx(1, dgettext(TEXT_DOMAIN,
+ "tecla initialization failed"));
+
+ if (gl_customize_completion(gl, NULL,
+ match_fn) != 0) {
+ (void) del_GetLine(gl);
+ errx(1, dgettext(TEXT_DOMAIN,
+ "tab completion failed to initialize"));
+ }
+
+ /*
+ * In interactive mode we only want to terminate
+ * when explicitly requested (e.g. by a command).
+ */
+ (void) sigset(SIGINT, SIG_IGN);
+ }
+ } else {
+ readfile = B_TRUE;
+ }
+}
+
+/*
+ * free tecla data structure
+ */
+static void
+fini_interactive(void)
+{
+ if (gl != NULL)
+ (void) del_GetLine(gl);
+}
+
+/*
+ * Get single input line, wrapping around interactive and non-interactive
+ * mode.
+ */
+static char *
+do_getstr(FILE *infile, char *prompt, char *ibuf, size_t ibuf_size)
+{
+ char *line;
+
+ if (infile != stdin)
+ return (fgets(ibuf, ibuf_size, infile));
+
+ /*
+ * If the user hits ^C then we want to catch it and
+ * start over. If the user hits EOF then we want to
+ * bail out.
+ */
+once_again:
+ line = gl_get_line(gl, prompt, NULL, -1);
+ if (gl_return_status(gl) == GLR_SIGNAL) {
+ gl_abandon_line(gl);
+ goto once_again;
+ } else if (gl_return_status(gl) == GLR_ERROR) {
+ gl_abandon_line(gl);
+ errx(1, dgettext(TEXT_DOMAIN, "Error reading terminal: %s\n"),
+ gl_error_message(gl, NULL, 0));
+ } else {
+ if (line != NULL) {
+ if (strlcpy(ibuf, line, ibuf_size) >= ibuf_size)
+ warnx(dgettext(TEXT_DOMAIN,
+ "Line too long (max=%d chars)"),
+ ibuf_size);
+ line = ibuf;
+ }
+ }
+
+ return (line);
+}
+
+/*
* Enter a mode where commands are read from a file. Treat stdin special.
*/
void
do_interactive(FILE *infile, char *configfile, char *promptstring,
- char *my_fmri, parse_cmdln_fn parseit)
+ char *my_fmri, parse_cmdln_fn parseit, CplMatchFn *match_fn)
{
char ibuf[IBUF_SIZE], holder[IBUF_SIZE];
char *hptr, **thisargv, *ebuf;
int thisargc;
boolean_t continue_in_progress = B_FALSE;
+ char *s;
(void) setjmp(env);
@@ -454,14 +540,10 @@ do_interactive(FILE *infile, char *configfile, char *promptstring,
interactive = B_TRUE;
bzero(ibuf, IBUF_SIZE);
- if (infile == stdin) {
- (void) printf("%s", promptstring);
- (void) fflush(stdout);
- } else {
- readfile = B_TRUE;
- }
+ /* panics for us */
+ init_interactive(infile, match_fn);
- while (fgets(ibuf, IBUF_SIZE, infile) != NULL) {
+ while ((s = do_getstr(infile, promptstring, ibuf, IBUF_SIZE)) != NULL) {
if (readfile)
lineno++;
thisargc = 0;
@@ -472,8 +554,15 @@ do_interactive(FILE *infile, char *configfile, char *promptstring,
* be null-terminated because of fgets().
*/
if (ibuf[IBUF_SIZE - 2] != '\0') {
- ipsecutil_exit(SERVICE_FATAL, my_fmri, debugfile,
- dgettext(TEXT_DOMAIN, "Line %d too big."), lineno);
+ if (infile == stdin) {
+ /* do_getstr() issued a warning already */
+ bzero(ibuf, IBUF_SIZE);
+ continue;
+ } else {
+ ipsecutil_exit(SERVICE_FATAL, my_fmri,
+ debugfile, dgettext(TEXT_DOMAIN,
+ "Line %d too big."), lineno);
+ }
}
if (!continue_in_progress) {
@@ -621,9 +710,14 @@ do_interactive(FILE *infile, char *configfile, char *promptstring,
lines_added);
}
} else {
- (void) putchar('\n');
+ /* no newline upon Ctrl-D */
+ if (s != NULL)
+ (void) putchar('\n');
(void) fflush(stdout);
}
+
+ fini_interactive();
+
EXIT_OK(NULL);
}
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.h b/usr/src/lib/libipsecutil/common/ipsec_util.h
index 83c2834f46..350b423df9 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.h
@@ -45,6 +45,7 @@ extern "C" {
#include <err.h>
#include <errfp.h>
#include <net/pfpolicy.h>
+#include <libtecla.h>
#ifndef A_CNT
/* macros for array manipulation */
@@ -54,10 +55,16 @@ extern "C" {
/* used for file parsing */
#define NBUF_SIZE 16
-#define IBUF_SIZE 2048
#define COMMENT_CHAR '#'
#define CONT_CHAR '\\'
#define QUOTE_CHAR '"'
+/*
+ * Input buffer size limits maximum line length for both file parsing and
+ * interactive mode. 4K chars should be enough even for broad commands and
+ * all possible key lenghts of today's symmetric ciphers entered via
+ * ipseckey(1M) which has the most bifurcated grammar from all IPsec commands.
+ */
+#define IBUF_SIZE 4096
/* used for command-line parsing */
#define START_ARG 8
@@ -163,7 +170,8 @@ extern boolean_t dump_sadb_idtype(uint8_t, FILE *, int *);
/* callback function passed in to do_interactive() */
typedef void (*parse_cmdln_fn)(int, char **, char *, boolean_t);
-extern void do_interactive(FILE *, char *, char *, char *, parse_cmdln_fn);
+extern void do_interactive(FILE *, char *, char *, char *, parse_cmdln_fn,
+ CplMatchFn *);
extern uint_t lines_parsed;
extern uint_t lines_added;