From 8c0a939ecd6c4b75271c65281e53ce78c37a57fe Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 22 Feb 2002 23:45:20 +0000 Subject: [PATCH 01/16] Add option to change the listen(2) parameter. Receive `fw'-specific code from `conf.c'. --- fw.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 4 deletions(-) diff --git a/fw.c b/fw.c index a53d515..c2c345c 100644 --- a/fw.c +++ b/fw.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: fw.c,v 1.12 2002/01/13 14:49:17 mdw Exp $ + * $Id: fw.c,v 1.13 2002/02/22 23:45:20 mdw Exp $ * * Port forwarding thingy * @@ -29,6 +29,10 @@ /*----- Revision history --------------------------------------------------* * * $Log: fw.c,v $ + * Revision 1.13 2002/02/22 23:45:20 mdw + * Add option to change the listen(2) parameter. Receive `fw'-specific + * code from `conf.c'. + * * Revision 1.12 2002/01/13 14:49:17 mdw * Track @dstr_vputf@ change. * @@ -103,8 +107,10 @@ #include "endpt.h" #include "exec.h" #include "fattr.h" +#include "file.h" #include "fw.h" #include "scan.h" +#include "socket.h" #include "source.h" /*----- Global variables --------------------------------------------------*/ @@ -126,7 +132,179 @@ static conffile *conffiles = 0; /* List of configuration files */ #define FW_QUIET 2u #define FW_SET 4u -/*----- Main code ---------------------------------------------------------*/ +/*----- Configuration parsing ---------------------------------------------*/ + +/* --- @parse@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner definition + * + * Returns: --- + * + * Use: Parses a configuration file from the scanner. + */ + +static source_ops *sources[] = + { &xsource_ops, &fsource_ops, &ssource_ops, 0 }; +static target_ops *targets[] = + { &xtarget_ops, &ftarget_ops, &starget_ops, 0 }; + +void parse(scanner *sc) +{ + token(sc); + + for (;;) { + if (sc->t == CTOK_EOF) + break; + if (sc->t != CTOK_WORD) + error(sc, "parse error, keyword expected"); + + /* --- Handle a forwarding request --- */ + + if (strcmp(sc->d.buf, "forward") == 0 || + strcmp(sc->d.buf, "fw") == 0 || + strcmp(sc->d.buf, "from") == 0) { + source *s; + target *t; + + token(sc); + + /* --- Read a source description --- */ + + { + source_ops **sops; + + /* --- Try to find a source type which understands --- */ + + s = 0; + for (sops = sources; *sops; sops++) { + if ((s = (*sops)->read(sc)) != 0) + goto found_source; + } + error(sc, "unknown source name `%s'", sc->d.buf); + + /* --- Read any source-specific options --- */ + + found_source: + if (sc->t == '{') { + token(sc); + while (sc->t == CTOK_WORD) { + if (!s->ops->option || !s->ops->option(s, sc)) { + error(sc, "unknown %s source option `%s'", + s->ops->name, sc->d.buf); + } + if (sc->t == ';') + token(sc); + } + if (sc->t != '}') + error(sc, "parse error, missing `}'"); + token(sc); + } + } + + /* --- Read a destination description --- */ + + if (sc->t == CTOK_WORD && (strcmp(sc->d.buf, "to") == 0 || + strcmp(sc->d.buf, "->") == 0)) + token(sc); + + { + target_ops **tops; + + /* --- Try to find a target which understands --- */ + + t = 0; + for (tops = targets; *tops; tops++) { + if ((t = (*tops)->read(sc)) != 0) + goto found_target; + } + error(sc, "unknown target name `%s'", sc->d.buf); + + /* --- Read any target-specific options --- */ + + found_target: + if (sc->t == '{') { + token(sc); + while (sc->t == CTOK_WORD) { + if (!t->ops->option || !t->ops->option(t, sc)) { + error(sc, "unknown %s target option `%s'", + t->ops->name, sc->d.buf); + } + if (sc->t == ';') + token(sc); + } + if (sc->t != '}') + error(sc, "parse error, `}' expected"); + token(sc); + } + } + + /* --- Combine the source and target --- */ + + s->ops->attach(s, sc, t); + } + + /* --- Include configuration from a file --- * + * + * Slightly tricky. Scan the optional semicolon from the including + * stream, not the included one. + */ + + else if (strcmp(sc->d.buf, "include") == 0) { + FILE *fp; + dstr d = DSTR_INIT; + + token(sc); + conf_name(sc, '/', &d); + if ((fp = fopen(d.buf, "r")) == 0) + error(sc, "can't include `%s': %s", d.buf, strerror(errno)); + if (sc->t == ';') + token(sc); + pushback(sc); + scan_push(sc, scan_file(fp, d.buf, 0)); + token(sc); + dstr_destroy(&d); + continue; /* Don't parse a trailing `;' */ + } + + /* --- Other configuration is handled elsewhere --- */ + + else { + + /* --- First try among the sources --- */ + + { + source_ops **sops; + + for (sops = sources; *sops; sops++) { + if ((*sops)->option && (*sops)->option(0, sc)) + goto found_option; + } + } + + /* --- Then try among the targets --- */ + + { + target_ops **tops; + + for (tops = targets; *tops; tops++) { + if ((*tops)->option && (*tops)->option(0, sc)) + goto found_option; + } + } + + /* --- Nobody wants the option --- */ + + error(sc, "unknown global option or prefix `%s'", sc->d.buf); + + found_option:; + } + + if (sc->t == ';') + token(sc); + } +} + +/*----- General utility functions -----------------------------------------*/ /* --- @fw_log@ --- * * @@ -269,10 +447,12 @@ static void fw_reload(int n, void *p) else scan_add(&sc, scan_file(fp, cf->name, 0)); } - conf_parse(&sc); + parse(&sc); fw_log(-1, "... reload completed OK"); } +/*----- Startup and options parsing ---------------------------------------*/ + /* --- Standard GNU help options --- */ static void version(FILE *fp) @@ -411,8 +591,11 @@ Exec options\n\ \n\ Socket options\n\ socket.conn [=] number|unlimited|one-shot\n\ + socket.listen [=] number\n\ socket.logging [=] yes|no\n\ +\n\ socket.inet.[allow|deny] [from] address [/ address]\n\ +\n\ socket.unix.fattr.*\n\ "); } @@ -593,7 +776,7 @@ int main(int argc, char *argv[]) /* --- Parse the configuration now gathered --- */ - conf_parse(&sc); + parse(&sc); /* --- Set up some signal handlers --- * * -- 2.11.0 From 23be5eb020ce25ee3890daf09c6dc637e0738cdb Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 23 Feb 2002 00:05:12 +0000 Subject: [PATCH 02/16] Fix spacing around full stops (at last!). --- fw.1 | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/fw.1 b/fw.1 index 3376b60..140f0f5 100644 --- a/fw.1 +++ b/fw.1 @@ -1,6 +1,6 @@ .\" -*-nroff-*- .\" -.\" $Id: fw.1,v 1.13 2002/02/22 23:45:01 mdw Exp $ +.\" $Id: fw.1,v 1.14 2002/02/23 00:05:12 mdw Exp $ .\" .\" Manual page for fw .\" @@ -28,6 +28,9 @@ .\" ---- Revision history --------------------------------------------------- .\" .\" $Log: fw.1,v $ +.\" Revision 1.14 2002/02/23 00:05:12 mdw +.\" Fix spacing around full stops (at last!). +.\" .\" Revision 1.13 2002/02/22 23:45:01 mdw .\" Add option to change the listen(2) parameter. .\" @@ -436,7 +439,7 @@ The syntax for qualifying options is like this: .br | .I prefix -.B . +.B .\& .I q-option .br | @@ -586,7 +589,7 @@ sources and targets is like this: .I file ::= .B file -.RB [ . ] +.RB [ .\& ] .I fspec .RB [ , .IR fspec ] @@ -743,7 +746,7 @@ exec .I exec ::= .BR exec -.RB [ . ] +.RB [ .\& ] .I cmd-spec .br .I cmd-spec @@ -949,7 +952,7 @@ The syntax for socket sources and targets is: .br .I socket-source ::= -.RB [ socket [ . ]] +.RB [ socket [ .\& ]] .RB [[ : ] \c .IR addr-type \c .RB [ : ]] @@ -957,7 +960,7 @@ The syntax for socket sources and targets is: .br .I socket-target ::= -.RB [ socket [ . ]] +.RB [ socket [ .\& ]] .RB [[ : ] \c .IR addr-type \c .RB [ : ]] @@ -1046,7 +1049,7 @@ source and target addresses have the following syntax: .br .I addr-elt ::= -.B . +.B .\& | .I word .GE @@ -1237,7 +1240,7 @@ just logs a message about the signal and continues. .br | .I prefix -.B . +.B .\& .I q-option .br | @@ -1262,7 +1265,7 @@ just logs a message about the signal and continues. .I file ::= .B file -.RB [ . ] +.RB [ .\& ] .I fspec .RB [ , .IR fspec ] @@ -1323,7 +1326,7 @@ exec .I exec ::= .BR exec -.RB [ . ] +.RB [ .\& ] .I cmd-spec .br .I cmd-spec @@ -1363,7 +1366,7 @@ exec .br .I socket-source ::= -.RB [ socket [ . ]] +.RB [ socket [ .\& ]] .RB [[ : ] \c .IR addr-type \c .RB [ : ]] @@ -1371,7 +1374,7 @@ exec .br .I socket-target ::= -.RB [ socket [ . ]] +.RB [ socket [ .\& ]] .RB [[ : ] \c .IR addr-type \c .RB [ : ]] @@ -1398,7 +1401,7 @@ exec .br .I addr-elt ::= -.B . +.B .\& | .I word .PP -- 2.11.0 From fed9ddde71db87a23d0fda6be6f7631d1a5207bf Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 23 Feb 2002 00:08:00 +0000 Subject: [PATCH 03/16] Fix stupid bugs from the listen(2) change. --- socket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/socket.c b/socket.c index 60d3d84..87b3d96 100644 --- a/socket.c +++ b/socket.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: socket.c,v 1.8 2002/02/22 23:44:44 mdw Exp $ + * $Id: socket.c,v 1.9 2002/02/23 00:08:00 mdw Exp $ * * Socket source and target definitions * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: socket.c,v $ + * Revision 1.9 2002/02/23 00:08:00 mdw + * Fix stupid bugs from the listen(2) change. + * * Revision 1.8 2002/02/22 23:44:44 mdw * Call @xfree@ rather than @free@. Add option to change the listen(2) * parameter. @@ -351,6 +354,7 @@ static int ssource_option(source *s, scanner *sc) sso->listen = atoi(sc->d.buf); if (sso->listen == 0) error(sc, "argument of `listen' must be positive"); + token(sc); CONF_ACCEPT; } @@ -607,7 +611,7 @@ static void ssource_attach(source *s, scanner *sc, target *t) /* --- Set it to listen for connections --- */ - if (listen(fd, 5)) + if (listen(fd, ss->o.listen)) error(sc, "couldn't listen on socket: %s", strerror(errno)); } -- 2.11.0 From 69ece10d5978cc250df4c643d034d766c2b4855a Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 24 Jan 2003 20:11:14 +0000 Subject: [PATCH 04/16] Don't do resource limits on Cygwin. --- acconfig.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/acconfig.h b/acconfig.h index b0f0d47..16ef2a6 100644 --- a/acconfig.h +++ b/acconfig.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: acconfig.h,v 1.2 1999/07/26 23:29:02 mdw Exp $ + * $Id: acconfig.h,v 1.3 2003/01/24 20:11:14 mdw Exp $ * * Configuration header for fw * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: acconfig.h,v $ + * Revision 1.3 2003/01/24 20:11:14 mdw + * Don't do resource limits on Cygwin. + * * Revision 1.2 1999/07/26 23:29:02 mdw * Add DECL_ENVIRON. * @@ -58,6 +61,13 @@ @BOTTOM@ + /* Cygwin advertises a number of limits and raises errors if you use them. + * This is a bit crap, and we ought to be able to cope, but for now we just + * don't do resource limits on Cygwin. Sorry. */ +#ifdef __CYGWIN__ +# undef HAVE_SETRLIMIT +#endif + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus -- 2.11.0 From 71db0fbd81336df4f91a981f9edccc08bc4f8f37 Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 24 Jan 2003 20:12:26 +0000 Subject: [PATCH 05/16] Correctly cast uid and gid sentinel values. Parse full filenames in exec arguments (can't do it for program, unfortunately, since the die is cast). --- exec.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 1f0102b..54a6547 100644 --- a/exec.c +++ b/exec.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: exec.c,v 1.6 2002/02/22 23:43:32 mdw Exp $ + * $Id: exec.c,v 1.7 2003/01/24 20:12:26 mdw Exp $ * * Source and target for executable programs * @@ -29,6 +29,11 @@ /*----- Revision history --------------------------------------------------* * * $Log: exec.c,v $ + * Revision 1.7 2003/01/24 20:12:26 mdw + * Correctly cast uid and gid sentinel values. Parse full filenames in + * exec arguments (can't do it for program, unfortunately, since the die is + * cast). + * * Revision 1.6 2002/02/22 23:43:32 mdw * Call @xfree@ rather than @free@. * @@ -591,7 +596,7 @@ static void xept_attach(endpt *e, reffd *in, reffd *out) /* --- Set group id --- */ - if (xo->gid != -1) { + if (xo->gid != (gid_t)-1) { if (setgid(xo->gid)) { moan("couldn't set gid %i: %s", xo->gid, strerror(errno)); _exit(1); @@ -605,7 +610,7 @@ static void xept_attach(endpt *e, reffd *in, reffd *out) /* --- Set uid --- */ - if (xo->uid != -1) { + if (xo->uid != (uid_t)-1) { if (setuid(xo->uid)) { moan("couldn't set uid %i: %s", xo->uid, strerror(errno)); _exit(1); @@ -787,7 +792,9 @@ static endpt_ops xept_ops = { xept_attach, xept_file, 0, xept_close }; void exec_init(void) { +#ifdef HAVE_SETRLIMIT rlimit_get(&exec_opts.xl); +#endif sig_add(&xept_sig, SIGCHLD, xept_chld, 0); sym_create(&env); env_import(&env, environ); @@ -892,8 +899,10 @@ static int exec_option(xdata *x, scanner *sc) /* --- Now try resource limit settings --- */ +#ifdef HAVE_SETRLIMIT if (rlimit_option(&xo->xl, sc)) CONF_ACCEPT; +#endif /* --- And then environment settings --- */ @@ -971,8 +980,12 @@ static void exec_read(xdata *x, scanner *sc) char *p, *q; char **v; - /* --- Strip off the leading `[' --- */ + /* --- Strip off the leading `[' --- * + * + * Allow various handy filename characters to be entered without quoting. + */ + conf_undelim(sc, "=:/.", "=:/."); token(sc); /* --- Read a sequence of arguments --- */ @@ -982,6 +995,7 @@ static void exec_read(xdata *x, scanner *sc) token(sc); argc++; } + conf_undelim(sc, 0, 0); /* --- Expect the closing `]' --- */ -- 2.11.0 From 00e3c0f1bbe99682debd4e34d3d3bd950f8c30cb Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 24 Jan 2003 20:12:40 +0000 Subject: [PATCH 06/16] Correctly cast uid and gid sentinel values. --- fw.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fw.c b/fw.c index c2c345c..b0eed70 100644 --- a/fw.c +++ b/fw.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: fw.c,v 1.13 2002/02/22 23:45:20 mdw Exp $ + * $Id: fw.c,v 1.14 2003/01/24 20:12:40 mdw Exp $ * * Port forwarding thingy * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: fw.c,v $ + * Revision 1.14 2003/01/24 20:12:40 mdw + * Correctly cast uid and gid sentinel values. + * * Revision 1.13 2002/02/22 23:45:20 mdw * Add option to change the listen(2) parameter. Receive `fw'-specific * code from `conf.c'. @@ -797,12 +800,12 @@ int main(int argc, char *argv[]) /* --- Drop privileges --- */ #ifdef HAVE_SETGROUPS - if ((dropg != -1 && (setgid(dropg) || setgroups(1, &dropg))) || - (drop != -1 && setuid(drop))) + if ((dropg != (gid_t)-1 && (setgid(dropg) || setgroups(1, &dropg))) || + (drop != (uid_t)-1 && setuid(drop))) die(1, "couldn't drop privileges: %s", strerror(errno)); #else - if ((dropg != -1 && setgid(dropg)) || - (drop != -1 && setuid(drop))) + if ((dropg != (gid_t)-1 && setgid(dropg)) || + (drop != (uid_t)-1 && setuid(drop))) die(1, "couldn't drop privileges: %s", strerror(errno)); #endif -- 2.11.0 From 49f5947bfdf0d8f2102365b7b66094695931ac02 Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 24 Jan 2003 20:13:04 +0000 Subject: [PATCH 07/16] Fix bogus examples. Explain quoting rules for `exec' endpoints. --- fw.1 | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fw.1 b/fw.1 index 140f0f5..4419f14 100644 --- a/fw.1 +++ b/fw.1 @@ -1,6 +1,6 @@ .\" -*-nroff-*- .\" -.\" $Id: fw.1,v 1.14 2002/02/23 00:05:12 mdw Exp $ +.\" $Id: fw.1,v 1.15 2003/01/24 20:13:04 mdw Exp $ .\" .\" Manual page for fw .\" @@ -28,6 +28,9 @@ .\" ---- Revision history --------------------------------------------------- .\" .\" $Log: fw.1,v $ +.\" Revision 1.15 2003/01/24 20:13:04 mdw +.\" Fix bogus examples. Explain quoting rules for `exec' endpoints. +.\" .\" Revision 1.14 2002/02/23 00:05:12 mdw .\" Fix spacing around full stops (at last!). .\" @@ -785,6 +788,15 @@ otherwise the file named by the first argument .RI ( argv0 ) is used. .PP +Note that the shell command or program name string must, if present, +have any delimiter characters (including +.RB ` / ' +and +.RB ` . ') +quoted; this is not required in the +.RB ` [ '-enclosed +argument list. +.PP The standard input and output of the program are forwarded to the other end of the connection. The standard error stream is caught by .B fw @@ -1142,7 +1154,7 @@ from file stdin, stdout to unix:/tmp/fortunes To emulate .BR cat (1): .VS -from stdin, null to null, stdout +from file stdin, null to file null, stdout .VE . .\"-------------------------------------------------------------------------- -- 2.11.0 From 75d4484771fe55c41858ed1c289388ebde6ee8f0 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 17 May 2003 12:33:55 +0000 Subject: [PATCH 08/16] Version bump. --- configure.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 7d14f84..6b7f0f3 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl -*-fundamental-*- dnl -dnl $Id: configure.in,v 1.13 2002/01/13 14:48:39 mdw Exp $ +dnl $Id: configure.in,v 1.14 2003/05/17 12:33:55 mdw Exp $ dnl dnl Configuration script for fw dnl @@ -28,6 +28,9 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. dnl ----- Revision history -------------------------------------------------- dnl dnl $Log: configure.in,v $ +dnl Revision 1.14 2003/05/17 12:33:55 mdw +dnl Version bump. +dnl dnl Revision 1.13 2002/01/13 14:48:39 mdw dnl Check for @getnetbyname@, since it appears not to be available under dnl Cygwin. @@ -55,7 +58,7 @@ dnl Initial revision. dnl AC_INIT(fw.c) -AM_INIT_AUTOMAKE(fw, 1.2.5) +AM_INIT_AUTOMAKE(fw, 1.2.6) AM_CONFIG_HEADER(config.h) AC_PROG_CC -- 2.11.0 From 08cb0dd89765683f47206905c9116b73949fee63 Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 31 Oct 2003 13:56:14 +0000 Subject: [PATCH 09/16] Fix data corruption in channel\! --- chan.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/chan.c b/chan.c index ffec633..2e483cd 100644 --- a/chan.c +++ b/chan.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: chan.c,v 1.5 2000/07/19 17:55:43 mdw Exp $ + * $Id: chan.c,v 1.6 2003/10/31 13:56:14 mdw Exp $ * * Channel management * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: chan.c,v $ + * Revision 1.6 2003/10/31 13:56:14 mdw + * Fix data corruption in channel\! + * * Revision 1.5 2000/07/19 17:55:43 mdw * (writechan): Pointless tweak: when the buffer is empty, reset the start * pointer to the beginning. This saves doing slightly trickier @@ -69,6 +72,12 @@ #include "chan.h" #include "fw.h" +#ifdef CHAN_DEBUG +# define D(x) x +#else +# define D(x) +#endif + /*----- Main code ---------------------------------------------------------*/ /* --- @writechan@ --- * @@ -95,16 +104,22 @@ static void writechan(int fd, unsigned mode, void *vp) /* --- Do the write --- */ - if (base + len <= CHAN_BUFSZ) + D( printf("writechan %d: base = %u, len = %u; ", fd, base, len); ) + if (base + len <= CHAN_BUFSZ) { + D( printf("%u:%u", base, len); ) w = write(fd, c->buf + base, len); - else { + } else { struct iovec iov[2]; iov[0].iov_base = c->buf + base; iov[0].iov_len = CHAN_BUFSZ - base; iov[1].iov_base = c->buf; iov[1].iov_len = len - iov[0].iov_len; + D( printf("%u:%u, %u:%u", + base, CHAN_BUFSZ - base, + 0, len + base - CHAN_BUFSZ); ) w = writev(fd, iov, 2); } + D( printf("; returned %d\n", w); ) /* --- Sift through the results --- */ @@ -118,6 +133,7 @@ static void writechan(int fd, unsigned mode, void *vp) else if (c->len == CHAN_BUFSZ && !(c->f & CHANF_CLOSE)) sel_addfile(&c->r); c->len -= w; + c->base += w; } if (c->len == 0) sel_rmfile(&c->w); @@ -153,21 +169,30 @@ static void readchan(int fd, unsigned mode, void *vp) { chan *c = vp; int r; - unsigned base = (c->base + c->len) & (CHAN_BUFSZ - 1); - unsigned len = CHAN_BUFSZ - c->len; + unsigned base = c->base; + unsigned len = c->len; /* --- Do the read --- */ - if (base + len <= CHAN_BUFSZ) - r = read(fd, c->buf + base, len); - else { + D( printf("readchan %d: base = %u, len = %u; ", fd, base, len); ) + if (base == 0) { + D( printf("%u:%u", len, CHAN_BUFSZ - len); ) + r = read(fd, c->buf + len, CHAN_BUFSZ - len); + } else if (base + len >= CHAN_BUFSZ) { + D( printf("%u:%u", base + len - CHAN_BUFSZ, CHAN_BUFSZ - len); ) + r = read(fd, c->buf + base + len - CHAN_BUFSZ, CHAN_BUFSZ - len); + } else { struct iovec iov[2]; - iov[0].iov_base = c->buf + base; - iov[0].iov_len = CHAN_BUFSZ - base; + iov[0].iov_base = c->buf + base + len; + iov[0].iov_len = CHAN_BUFSZ - base - len; iov[1].iov_base = c->buf; - iov[1].iov_len = len - iov[0].iov_len; + iov[1].iov_len = base; + D( printf("%u:%u, %u:%u", + base + len, CHAN_BUFSZ - base - len, + 0, base); ) r = readv(fd, iov, 2); } + D( printf("; returned %d\n", r); ) /* --- Sift through the results --- */ -- 2.11.0 From 0ac54f22a766f068db98e1caecbc913cb0cfd191 Mon Sep 17 00:00:00 2001 From: mdw Date: Tue, 25 Nov 2003 14:08:23 +0000 Subject: [PATCH 10/16] Debianization. Socket target options. Internet binding. --- .cvsignore | 1 + Makefile.am | 9 +- acl.c | 158 ++++++++++++++++++++++----------- acl.h | 56 +++++++++--- addr.h | 111 ++++++++++++++++------- conf.h | 7 +- configure.in | 9 +- debian/.cvsignore | 2 + debian/changelog | 11 +++ debian/control | 17 ++++ debian/copyright | 16 ++++ debian/rules | 45 ++++++++++ inet.c | 258 +++++++++++++++++++++++++++++++++++++++++++----------- socket.c | 133 ++++++++++++++-------------- socket.h | 19 +++- target.h | 9 +- un.c | 61 ++++++++++--- 17 files changed, 691 insertions(+), 231 deletions(-) create mode 100644 debian/.cvsignore create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules diff --git a/.cvsignore b/.cvsignore index 19a3c54..4b605eb 100644 --- a/.cvsignore +++ b/.cvsignore @@ -5,3 +5,4 @@ build config.h.in configure stamp-h.in +deb-build diff --git a/Makefile.am b/Makefile.am index 2c270c7..c9598c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## -*-makefile-*- ## -## $Id: Makefile.am,v 1.5 1999/11/11 19:08:27 mdw Exp $ +## $Id: Makefile.am,v 1.6 2003/11/25 14:08:23 mdw Exp $ ## ## Makefile for fw ## @@ -28,6 +28,9 @@ ##----- Revision history ---------------------------------------------------- ## ## $Log: Makefile.am,v $ +## Revision 1.6 2003/11/25 14:08:23 mdw +## Debianization. Socket target options. Internet binding. +## ## Revision 1.5 1999/11/11 19:08:27 mdw ## Build separately from mLib. ## @@ -49,7 +52,9 @@ AUTOMAKE_OPTIONS = foreign bin_PROGRAMS = fw man_MANS = fw.1 -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = \ + $(man_MANS) \ + debian/changelog debian/copyright debian/control debian/rules fw_SOURCES = \ chan.c conf.c endpt.c fw.c reffd.c scan.c \ diff --git a/acl.c b/acl.c index 059ec9c..29dd2db 100644 --- a/acl.c +++ b/acl.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: acl.c,v 1.3 1999/07/27 18:30:53 mdw Exp $ + * $Id: acl.c,v 1.4 2003/11/25 14:08:23 mdw Exp $ * * Access control list handling * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: acl.c,v $ + * Revision 1.4 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.3 1999/07/27 18:30:53 mdw * Various minor portability fixes. * @@ -61,38 +64,122 @@ #include "acl.h" -/*----- Static variables --------------------------------------------------*/ +/*----- Main code ---------------------------------------------------------*/ + +/* --- @acl_addhost@ --- * + * + * Arguments: @acl_entry ***a@ = address of pointer to list tail + * @unsigned act@ = what to do with matching addresses + * @struct in_addr addr, mask@ = address and mask to match + * + * Returns: --- + * + * Use: Adds a host-authentication entry to the end of an access + * control list. + */ + +static int acl_checkhost(void *aa, struct in_addr addr, unsigned port) +{ + acl_host *a = aa; + return ((addr.s_addr & a->mask.s_addr) == a->addr.s_addr); +} -static acl_entry *global = 0; -static acl_entry **gtail = &global; +static void acl_dumphost(void *aa, FILE *fp) +{ + acl_host *a = aa; + + fputs("from ", fp); + fputs(inet_ntoa(a->addr), fp); + fputc('/', fp); + fputs(inet_ntoa(a->mask), fp); +} -/*----- Main code ---------------------------------------------------------*/ +static void acl_freehost(void *aa) +{ + acl_host *a = aa; + DESTROY(a); +} + +static const acl_ops acl_hostops = { + acl_checkhost, acl_dumphost, acl_freehost +}; + +void acl_addhost(acl_entry ***a, unsigned act, + struct in_addr addr, struct in_addr mask) +{ + acl_host *aa = CREATE(acl_host); + aa->a.next = 0; + aa->a.ops = &acl_hostops; + aa->a.act = act; + aa->addr.s_addr = addr.s_addr & mask.s_addr; + aa->mask = mask; + **a = &aa->a; + *a = &aa->a.next; +} + +/* --- @acl_addpriv@ --- * + * + * Arguments: @acl_entry ***a@ = address of pointer to list tail + * @unsigned act@ = what to do with matching addresses + * + * Returns: --- + * + * Use: Adds a privileged-port check to the end of an access control + * list. + */ + +static int acl_checkpriv(void *aa, struct in_addr addr, unsigned port) +{ + return (port < 1024); +} + +static void acl_dumppriv(void *aa, FILE *fp) +{ + fputs("from privileged ports", fp); +} + +static void acl_freepriv(void *aa) +{ + acl_entry *a = aa; + DESTROY(a); +} + +static const acl_ops acl_privops = { + acl_checkpriv, acl_dumppriv, acl_freepriv +}; + +void acl_addpriv(acl_entry ***a, unsigned act) +{ + acl_entry *aa = CREATE(acl_entry); + aa->next = 0; + aa->ops = &acl_privops; + aa->act = act; + **a = aa; + *a = &aa->next; +} /* --- @acl_check@ --- * * * Arguments: @acl_entry *a@ = pointer to ACL to check against * @struct in_addr addr@ = address to check + * @unsigned port@ = port number to check + * @int *act@ = verdict (should initially be @ACT_ALLOW@) * - * Returns: Nonzero if allowed. + * Returns: Zero if undecided, nonzero if a rule matched. * * Use: Checks an address against an ACL. */ -int acl_check(acl_entry *a, struct in_addr addr) +int acl_check(acl_entry *a, struct in_addr addr, unsigned port, int *act) { - int act = ACL_ALLOW; - int i; - - for (i = 0; i < 2; i++) { - for (; a; a = a->next) { - if ((addr.s_addr & a->mask.s_addr) == a->addr.s_addr) - return (a->act & ACL_PERM); - act = (a->act & ACL_PERM) ^ 1; + for (; a; a = a->next) { + if (a->ops->check(a, addr, port)) { + *act = a->act & ACL_PERM; + return (1); } - a = global; + *act = (a->act & ACL_PERM) ^ 1; } - - return (act); + return (0); } /* --- @acl_dump@ --- * @@ -107,14 +194,10 @@ int acl_check(acl_entry *a, struct in_addr addr) void acl_dump(acl_entry *a, FILE *fp) { - if (!a) - a = global; for (; a; a = a->next) { - fprintf(fp, " %s from ", + fprintf(fp, " %s ", (a->act & ACL_PERM) == ACL_ALLOW ? "allow" : "deny"); - fputs(inet_ntoa(a->addr), fp); - fputc('/', fp); - fputs(inet_ntoa(a->mask), fp); + a->ops->dump(a, fp); fputc('\n', fp); } } @@ -133,33 +216,8 @@ void acl_free(acl_entry *a) while (a) { acl_entry *aa = a; a = a->next; - DESTROY(aa); + aa->ops->free(aa); } } -/* --- @acl_add@ --- * - * - * Arguments: @acl_entry ***a@ = address of pointer to list tail - * @unsigned act@ = what to do with matching addresses - * @struct in_addr addr, mask@ = address and mask to match - * - * Returns: --- - * - * Use: Adds an entry to the end of an access control list. - */ - -void acl_add(acl_entry ***a, unsigned act, - struct in_addr addr, struct in_addr mask) -{ - acl_entry *aa = CREATE(acl_entry); - aa->act = act; - aa->addr.s_addr = addr.s_addr & mask.s_addr; - aa->mask = mask; - aa->next = 0; - if (!a) - a = >ail; - **a = aa; - *a = &aa->next; -} - /*----- That's all, folks -------------------------------------------------*/ diff --git a/acl.h b/acl.h index 21f398d..373df4b 100644 --- a/acl.h +++ b/acl.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: acl.h,v 1.3 1999/07/27 18:30:53 mdw Exp $ + * $Id: acl.h,v 1.4 2003/11/25 14:08:23 mdw Exp $ * * Access control list handling * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: acl.h,v $ + * Revision 1.4 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.3 1999/07/27 18:30:53 mdw * Various minor portability fixes. * @@ -61,27 +64,46 @@ typedef struct acl_entry { struct acl_entry *next; /* Next entry in the list */ + const struct acl_ops *ops; /* Operations for the ACL entry */ unsigned act; /* What to do with matching hosts */ - struct in_addr addr, mask; /* Address and netmask */ } acl_entry; -#define ACL_DENY 0 /* Deny access to matching hosts */ -#define ACL_ALLOW 1 /* Allow access to matching hosts */ +#define ACL_DENY 0 /* Deny access to matching conns */ +#define ACL_ALLOW 1 /* Allow access to matching conns */ #define ACL_PERM 1u /* Bit mask for permission bit */ +/* --- Host-based access control --- */ + +typedef struct acl_host { + acl_entry a; /* Base structure */ + struct in_addr addr, mask; /* Address and netmask */ +} acl_host; + +/* --- ACL methods --- */ + +typedef struct acl_ops { + int (*check)(void */*a*/, struct in_addr /*addr*/, unsigned /*port*/); + void (*dump)(void */*a*/, FILE */*fp*/); + void (*free)(void */*a*/); +} acl_ops; + /*----- Functions provided ------------------------------------------------*/ /* --- @acl_check@ --- * * * Arguments: @acl_entry *a@ = pointer to ACL to check against * @struct in_addr addr@ = address to check + * @unsigned port@ = port number to check + * @int *act@ = verdict (should initially be @ACT_ALLOW@) * - * Returns: Nonzero if allowed. + * Returns: Zero if undecided, nonzero if a rule matched. * * Use: Checks an address against an ACL. */ -extern int acl_check(acl_entry */*a*/, struct in_addr /*addr*/); +extern int acl_check(acl_entry */*a*/, + struct in_addr /*addr*/, unsigned /*port*/, + int */*act*/); /* --- @acl_dump@ --- * * @@ -106,7 +128,7 @@ extern void acl_dump(acl_entry */*a*/, FILE */*fp*/); extern void acl_free(acl_entry */*a*/); -/* --- @acl_add@ --- * +/* --- @acl_addhost@ --- * * * Arguments: @acl_entry ***a@ = address of pointer to list tail * @unsigned act@ = what to do with matching addresses @@ -114,11 +136,25 @@ extern void acl_free(acl_entry */*a*/); * * Returns: --- * - * Use: Adds an entry to the end of an access control list. + * Use: Adds a host-authentication entry to the end of an access + * control list. + */ + +extern void acl_addhost(acl_entry ***/*a*/, unsigned /*act*/, + struct in_addr /*addr*/, struct in_addr /*mask*/); + +/* --- @acl_addpriv@ --- * + * + * Arguments: @acl_entry ***a@ = address of pointer to list tail + * @unsigned act@ = what to do with matching addresses + * + * Returns: --- + * + * Use: Adds a privileged-port check to the end of an access control + * list. */ -extern void acl_add(acl_entry ***/*a*/, unsigned /*act*/, - struct in_addr /*addr*/, struct in_addr /*mask*/); +extern void acl_addpriv(acl_entry ***/*a*/, unsigned /*act*/); /*----- That's all, folks -------------------------------------------------*/ diff --git a/addr.h b/addr.h index cc5b790..adc4cd1 100644 --- a/addr.h +++ b/addr.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: addr.h,v 1.2 1999/07/27 18:30:53 mdw Exp $ + * $Id: addr.h,v 1.3 2003/11/25 14:08:23 mdw Exp $ * * Generic interface to network address handlers * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: addr.h,v $ + * Revision 1.3 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.2 1999/07/27 18:30:53 mdw * Various minor portability fixes. * @@ -50,11 +53,16 @@ #include #include +#include #ifndef REFFD_H # include "reffd.h" #endif +#ifndef ENDPT_H +# include "endpt.h" +#endif + #ifndef SCAN_H # include "scan.h" #endif @@ -73,11 +81,6 @@ typedef struct addr { size_t sz; } addr; -typedef struct gen_addr { - addr a; - struct sockaddr sa; -} gen_addr; - #define ADDRSZ(sz) (sizeof(addr) + (sz)) /* --- Address configuration --- * @@ -99,14 +102,14 @@ typedef struct addr_opts { enum { ADDR_SRC, - ADDR_DEST + ADDR_DEST, + ADDR_GLOBAL }; /* --- Description of an address type handler --- */ typedef struct addr_ops { const char *name; /* Protocol's internal name */ - int pf; /* Protocol family number */ /* --- @read@ --- * * @@ -145,7 +148,7 @@ typedef struct addr_ops { void (*print)(addr */*a*/, unsigned /*type*/, dstr */*d*/); - /* --- @initopts@ --- * + /* --- @initsrcopts@ --- * * * Arguments: --- * @@ -156,19 +159,57 @@ typedef struct addr_ops { * are added to the block when necessary. */ - addr_opts *(*initopts)(void); + addr_opts *(*initsrcopts)(void); /* --- @option@ --- * * * Arguments: @scanner *sc@ = pointer to a scanner to read from + * @unsigned type@ = kind of option this is * @addr_opts *ao@ = data block to modify (from @init@), or null * * Returns: Nonzero to claim the option. * - * Use: Parses an option, either global or listener-specific. + * Use: Parses a source option, either global or listener-specific. + */ + + int (*option)(scanner */*sc*/, addr_opts */*ao*/, unsigned /*type*/); + + /* --- @freesrcopts@ --- * + * + * Arguments: @addr_opts *ao@ = data block to remove + * + * Returns: --- + * + * Use: Throws away all the configuration data for an address type. + */ + + void (*freesrcopts)(addr_opts */*ao*/); + + /* --- @bind@ --- * + * + * Arguments: @addr *a@ = the address to bind to + * @addr_opts *ao@ = the address options + * + * Returns: File descriptor of bound socket if OK, or @-1@ on error. + * + * Use: Binds a listening socket. The tedious stuff with @listen@ + * isn't necessary. + */ + + int (*bind)(addr */*a*/, addr_opts */*ao*/); + + /* --- @unbind@ --- * + * + * Arguments: @addr *a@ = pointer to an address + * + * Returns: --- + * + * Use: Unbinds an address. This is used when tidying up. The main + * purpose is to let the Unix-domain handler remove its socket + * node from the filesystem. */ - int (*option)(scanner */*sc*/, addr_opts */*ao*/); + void (*unbind)(addr */*a*/); /* --- @accept@ --- * * @@ -183,42 +224,52 @@ typedef struct addr_ops { reffd *(*accept)(int /*fd*/, addr_opts */*ao*/, const char */*desc*/); - /* --- @freeopts@ --- * + /* --- @inittargopts@ --- * * - * Arguments: @addr_opts *ao@ = data block to remove + * Arguments: --- * - * Returns: --- + * Returns: A pointer to a protocol-specific data block for a connecter * - * Use: Throws away all the configuration data for an address type. + * Use: Creates a data block for a target. This is attached to the + * target data structure. Options can then be requested, and + * are added to the block when necessary. */ - void (*freeopts)(addr_opts */*ao*/); + addr_opts *(*inittargopts)(void); - /* --- @bound@ --- * + /* --- @freetargopts@ --- * * - * Arguments: @addr *a@ = pointer to an address - * @addr_opts *ao@ = pointer to attributes block + * Arguments: @addr_opts *ao@ = data block to remove * * Returns: --- * - * Use: Reports that a file descriptor has been (successfully) bound - * to an address. + * Use: Throws away all the configuration data for an address type. */ - void (*bound)(addr */*a*/, addr_opts */*ao*/); + void (*freetargopts)(addr_opts */*ao*/); - /* --- @unbind@ --- * + /* --- @connect@ --- * * - * Arguments: @addr *a@ = pointer to an address + * Arguments: @addr *a@ = destination address + * @addr_opts *ao@ = target address options + * @conn *c@ = connection structure + * @endpt *e@ = endpoint structure * - * Returns: --- + * Returns: Zero if OK, @-1@ on some error. * - * Use: Unbinds an address. This is used when tidying up. The main - * purpose is to let the Unix-domain handler remove its socket - * node from the filesystem. + * Use: Requests that a connection be made, or at least set in + * motion. An address may do one of these things: + * + * * Return @-1@. + * + * * Call @starget_connected@ with @-1@ or a connected file + * descriptor and the pointer @e@. + * + * * Call @conn_init@ or @conn_fd@, giving @starget_connected@ + * and @e@ as the function to call. */ - void (*unbind)(addr */*a*/); + int (*connect)(addr */*a*/, addr_opts */*ao*/, conn */*c*/, endpt */*e*/); } addr_ops; diff --git a/conf.h b/conf.h index f9e25e9..7b656e0 100644 --- a/conf.h +++ b/conf.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: conf.h,v 1.7 2002/02/22 23:42:56 mdw Exp $ + * $Id: conf.h,v 1.8 2003/11/25 14:08:23 mdw Exp $ * * Configuration parsing * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: conf.h,v $ + * Revision 1.8 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.7 2002/02/22 23:42:56 mdw * `fw'-specific configuration code moved out. This file might become part * of a library some day. @@ -232,7 +235,7 @@ extern int conf_prefix(scanner */*sc*/, const char */*p*/); * because the option wasn't accepted. \ */ \ \ - goto _conf_reject; \ + goto _conf_reject; \ _conf_reject: \ if (_conf_state == CS_PLAIN) \ _conf_state = CS_UNKNOWN; \ diff --git a/configure.in b/configure.in index 6b7f0f3..446e361 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ -dnl -*-fundamental-*- +dnl -*-m4-*- dnl -dnl $Id: configure.in,v 1.14 2003/05/17 12:33:55 mdw Exp $ +dnl $Id: configure.in,v 1.15 2003/11/25 14:08:23 mdw Exp $ dnl dnl Configuration script for fw dnl @@ -28,6 +28,9 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. dnl ----- Revision history -------------------------------------------------- dnl dnl $Log: configure.in,v $ +dnl Revision 1.15 2003/11/25 14:08:23 mdw +dnl Debianization. Socket target options. Internet binding. +dnl dnl Revision 1.14 2003/05/17 12:33:55 mdw dnl Version bump. dnl @@ -73,7 +76,7 @@ mdw_DECL_ENVIRON mdw_CHECK_MANYLIBS(socket, socket) mdw_CHECK_MANYLIBS(gethostbyname, nsl resolv) -mdw_MLIB(1.7.0) +mdw_MLIB(2.0.2) AC_CHECK_FUNCS(inet_aton) AC_CHECK_FUNCS(setrlimit) diff --git a/debian/.cvsignore b/debian/.cvsignore new file mode 100644 index 0000000..fd2495d --- /dev/null +++ b/debian/.cvsignore @@ -0,0 +1,2 @@ +files tmp substvars *.substvars *.debhelper +fw diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..edbda91 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,11 @@ +fw (1.2.7) experimental; urgency=low + + * Debianization! + + * Fix data corruption in chan.c. + + * Socket target option support. Currently there's just bind address. + + * Support binding to specific addresses for inet sources and targets. + + -- Mark Wooding Tue, 25 Nov 2003 14:07:42 +0000 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d0a1a28 --- /dev/null +++ b/debian/control @@ -0,0 +1,17 @@ +Source: fw +Section: net +Priority: extra +Build-Depends: mlib-dev (>= 2.0.2), debhelper (>= 4.0.2) +Maintainer: Mark Wooding +Standards-Version: 3.1.1 + +Package: fw +Architecture: any +Depends: ${shlibs:Depends} +Description: Excessive port forwarder + fw can forward connections to and from: TCP sockets, Unix-domain sockets, + locally-executed programs, and file descriptors. It can do host-based + access control. It will log incoming TCP connections by hostname and + username (as reported by identd on the connecting host). It subsumes the + basic functionality of inetd, cat, netcat and others. It runs as a + single nonblocking process. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..6401701 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,16 @@ +fw is copyright (c) 2003 Straylight/Edgeware. + +fw 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. + +fw 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 a copy of the GNU General Public License in +/usr/share/common-licenses/GPL; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..d592b5b --- /dev/null +++ b/debian/rules @@ -0,0 +1,45 @@ +#! /usr/bin/make -f + +export DH_COMPAT = 4 + +build: + rm -rf build deb-build + mkdir deb-build + cd deb-build; ../configure --prefix=/usr --mandir=/usr/share/man + make -C deb-build + touch build + +clean: + dh_clean + rm -rf deb-build build + +install: build + dh_clean + make -C deb-build install DESTDIR=`pwd`/debian/fw + +binary-indep: + +binary-arch: install + dh_testdir -a + dh_testroot -a + dh_compress -a + dh_installdocs -a + dh_strip -a + dh_shlibdeps -a + dh_gencontrol -a + dh_fixperms -a + dh_installdeb -a + dh_md5sums -a + dh_builddeb -a + +binary: binary-indep binary-arch + +source: + rm -rf deb-build/*.tar.gz deb-build/=deb= + make -C deb-build dist + mkdir deb-build/=deb= + cd deb-build/=deb=; tar xvfz ../*.tar.gz + d=`pwd`; cd ..; dpkg-source -i -b $$d/deb-build/=deb=/* + rm -rf deb-build/=deb= + +.PHONY: binary binary-arch binary-indep clean install source diff --git a/inet.c b/inet.c index f98c7fa..70e5c90 100644 --- a/inet.c +++ b/inet.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: inet.c,v 1.4 2002/01/13 14:49:56 mdw Exp $ + * $Id: inet.c,v 1.5 2003/11/25 14:08:23 mdw Exp $ * * Protocol specific definitions for IPv4 sockets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: inet.c,v $ + * Revision 1.5 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.4 2002/01/13 14:49:56 mdw * Conditional compilation for @getnetbyname@, since Cygwin doesn't have * it. @@ -64,16 +67,19 @@ #include #include +#include #include #include #include "acl.h" #include "addr.h" #include "conf.h" +#include "fw.h" #include "identify.h" #include "inet.h" #include "reffd.h" #include "scan.h" +#include "socket.h" /*----- Data structures ---------------------------------------------------*/ @@ -84,9 +90,23 @@ typedef struct inet_addrx { typedef struct inet_opts { addr_opts ao; + struct in_addr bind; +} inet_opts; + +typedef struct inet_srcopts { + inet_opts io; acl_entry *acl; acl_entry **acltail; -} inet_opts; +} inet_srcopts; + +typedef struct inet_targopts { + inet_opts io; +} inet_targopts; + +static inet_srcopts inet_globalsrc = + { { { 0 }, { INADDR_ANY } }, 0, &inet_globalsrc.acl }; +static inet_targopts inet_globaltarg = + { { { 0 }, { INADDR_ANY } } }; /*----- Protocol operations -----------------------------------------------*/ @@ -168,24 +188,64 @@ static void inet_print(addr *a, unsigned type, dstr *d) /* --- @initopts@ --- */ -static addr_opts *inet_initopts(void) +static addr_opts *inet_initsrcopts(void) { - inet_opts *io = CREATE(inet_opts); + inet_srcopts *io = CREATE(inet_srcopts); + *io = inet_globalsrc; io->acl = 0; io->acltail = &io->acl; - return (&io->ao); + return (&io->io.ao); +} + +static addr_opts *inet_inittargopts(void) +{ + inet_targopts *io = CREATE(inet_targopts); + *io = inet_globaltarg; + return (&io->io.ao); } /* --- @option@ --- */ -static int inet_option(scanner *sc, addr_opts *ao) +static void addropt(scanner *sc, inet_opts *io) { - inet_opts *io = (inet_opts *)ao; + dstr d = DSTR_INIT; + struct hostent *h; - CONF_BEGIN(sc, "inet", "Internet socket") + token(sc); + if (sc->t == '=') + token(sc); + if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "any") == 0) + io->bind.s_addr = INADDR_ANY; + else { + conf_name(sc, '.', &d); + if ((h = gethostbyname(d.buf)) == 0) + error(sc, "couldn't resolve address `%s'", d.buf); + memcpy(&io->bind, h->h_addr, sizeof(struct in_addr)); + } +} +static int srcopt(scanner *sc, addr_opts *ao) +{ + inet_srcopts *io = (inet_srcopts *)ao; unsigned act; + CONF_BEGIN(sc, "source", "Internet socket source") + + /* --- Initialization --- */ + + if (!io) { + if (!inet_globalsrc.acltail) + inet_globalsrc.acltail = &inet_globalsrc.acl; + io = &inet_globalsrc; + } + + /* --- Source address configuration --- */ + + if (strcmp(sc->d.buf, "addr") == 0) { + addropt(sc, &io->io); + CONF_ACCEPT; + } + /* --- Access control limitations --- */ if ((strcmp(sc->d.buf, "allow") == 0 && (act = ACL_ALLOW, 1)) || @@ -195,50 +255,61 @@ static int inet_option(scanner *sc, addr_opts *ao) struct in_addr a, m; dstr d = DSTR_INIT; - /* --- Find the host or network address --- */ + /* --- Find out what's going on --- */ token(sc); if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "from") == 0) token(sc); - conf_name(sc, '.', &d); -#ifdef HAVE_GETNETBYNAME - if ((n = getnetbyname(d.buf)) != 0) - a.s_addr = htonl(n->n_net); - else -#endif - if ((h = gethostbyname(d.buf)) == 0) - error(sc, "couldn't resolve address `%s'", d.buf); - else - memcpy(&a, h->h_addr, sizeof(struct in_addr)); - - /* --- Find the netmask, if any --- */ - if (sc->t != '/') - m.s_addr = ~0ul; - else { + if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "priv-port") == 0) { + acl_addpriv(&io->acltail, act); token(sc); - DRESET(&d); + } else { + if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "host") == 0) + token(sc); + + /* --- Find the host or network address --- */ + conf_name(sc, '.', &d); - if (strchr(d.buf, '.') == 0) { - int n = atoi(d.buf); - if (n == 0) - m.s_addr = 0; +#ifdef HAVE_GETNETBYNAME + if ((n = getnetbyname(d.buf)) != 0) + a.s_addr = htonl(n->n_net); + else +#endif + if ((h = gethostbyname(d.buf)) == 0) + error(sc, "couldn't resolve address `%s'", d.buf); else - m.s_addr = htonl((~0ul << (32 - n)) & 0xffffffff); - } else { + memcpy(&a, h->h_addr, sizeof(struct in_addr)); + + /* --- Find the netmask, if any --- */ + + if (sc->t != '/') + m.s_addr = ~0ul; + else { + token(sc); + DRESET(&d); + conf_name(sc, '.', &d); + if (strchr(d.buf, '.') == 0) { + int n = atoi(d.buf); + if (n == 0) + m.s_addr = 0; + else + m.s_addr = htonl((~0ul << (32 - n)) & 0xffffffff); + } else { #ifdef HAVE_INET_ATON - if (!inet_aton(d.buf, &m)) - error(sc, "bad netmask `%s'", d.buf); + if (!inet_aton(d.buf, &m)) + error(sc, "bad netmask `%s'", d.buf); #else - m.s_addr = inet_addr(d.buf); + m.s_addr = inet_addr(d.buf); #endif + } } - } - dstr_destroy(&d); + dstr_destroy(&d); - /* --- Add the access control entry --- */ + /* --- Add the access control entry --- */ - acl_add(io ? &io->acltail : 0, act, a, m); + acl_addhost(&io->acltail, act, a, m); + } CONF_ACCEPT; } @@ -247,14 +318,78 @@ static int inet_option(scanner *sc, addr_opts *ao) CONF_END; } +static int targopt(scanner *sc, addr_opts *ao) +{ + inet_targopts *io = (inet_targopts *)ao; + + CONF_BEGIN(sc, "dest", "Internet socket target"); + if (strcmp(sc->d.buf, "addr") == 0) { + addropt(sc, &io->io); + CONF_ACCEPT; + } + CONF_END; +} + +static int inet_option(scanner *sc, addr_opts *ao, unsigned type) +{ + CONF_BEGIN(sc, "inet", "Internet socket"); + if (type != ADDR_DEST && srcopt(sc, ao)) + CONF_ACCEPT; + if (type != ADDR_SRC && targopt(sc, ao)) + CONF_ACCEPT; + CONF_END; +} + +/* --- @freeopts@ --- */ + +static void inet_freesrcopts(addr_opts *ao) +{ + inet_srcopts *io = (inet_srcopts *)ao; + acl_free(io->acl); + DESTROY(io); +} + +static void inet_freetargopts(addr_opts *ao) +{ + inet_targopts *io = (inet_targopts *)ao; + DESTROY(io); +} + +/* --- @bind@ --- */ + +static int inet_bind(addr *a, addr_opts *ao) +{ + inet_addrx *ia = (inet_addrx *)a; + inet_srcopts *io = (inet_srcopts *)ao; + struct sockaddr_in sin; + int opt = 1; + int fd; + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) + goto fail_0; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + sin = ia->sin; + sin.sin_addr = io->io.bind; + if (bind(fd, (struct sockaddr *)&sin, sizeof(ia->sin))) + goto fail_1; + return (fd); + +fail_1: + close(fd); +fail_0: + return (-1); +} + /* --- @accept@ --- */ static reffd *inet_accept(int fd, addr_opts *ao, const char *desc) { - inet_opts *io = (inet_opts *)ao; + inet_srcopts *io = (inet_srcopts *)ao; int nfd; id_req q; size_t lsinsz = sizeof(q.lsin), rsinsz = sizeof(q.rsin); + int act = ACL_ALLOW; /* --- Accept the new connection --- */ @@ -269,9 +404,12 @@ static reffd *inet_accept(int fd, addr_opts *ao, const char *desc) /* --- Find out whether this connection is allowed --- */ - if (!acl_check(io->acl, q.rsin.sin_addr)) { + if (!acl_check(io->acl, q.rsin.sin_addr, ntohs(q.rsin.sin_port), &act)) + acl_check(inet_globalsrc.acl, q.rsin.sin_addr, + ntohs(q.rsin.sin_port), &act); + if (act != ACL_ALLOW) { q.act = "refused"; - if (!(io->ao.f & ADDRF_NOLOG)) + if (!(io->io.ao.f & ADDRF_NOLOG)) identify(&q); REFFD_DEC(q.r); return (0); @@ -280,26 +418,48 @@ static reffd *inet_accept(int fd, addr_opts *ao, const char *desc) /* --- Everything seems to be OK --- */ q.act = "accepted"; - if (!(io->ao.f & ADDRF_NOLOG)) + if (!(io->io.ao.f & ADDRF_NOLOG)) identify(&q); return (q.r); } -/* --- @freeopts@ --- */ +/* --- @connect@ --- */ -static void inet_freeopts(addr_opts *ao) +static int inet_connect(addr *a, addr_opts *ao, conn *c, endpt *e) { - inet_opts *io = (inet_opts *)ao; - acl_free(io->acl); - DESTROY(ao); + inet_addrx *ia = (inet_addrx *)a; + inet_targopts *io = (inet_targopts *)ao; + int fd; + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) + goto fail_0; + if (io->io.bind.s_addr != INADDR_ANY) { + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = io->io.bind; + sin.sin_port = 0; + if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) + goto fail_1; + } + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + return (conn_init(c, sel, fd, (struct sockaddr *)&ia->sin, sizeof(ia->sin), + starget_connected, e)); +fail_1: + close(fd); +fail_0: + return (-1); } /* --- Ops table --- */ addr_ops inet_ops = { - "inet", PF_INET, + "inet", inet_read, inet_destroy, inet_print, - inet_initopts, inet_option, inet_accept, inet_freeopts, 0, 0 + inet_initsrcopts, inet_option, inet_freesrcopts, + inet_bind, 0, inet_accept, + inet_inittargopts, inet_freetargopts, + inet_connect }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/socket.c b/socket.c index 87b3d96..5f1a731 100644 --- a/socket.c +++ b/socket.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: socket.c,v 1.9 2002/02/23 00:08:00 mdw Exp $ + * $Id: socket.c,v 1.10 2003/11/25 14:08:23 mdw Exp $ * * Socket source and target definitions * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: socket.c,v $ + * Revision 1.10 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.9 2002/02/23 00:08:00 mdw * Fix stupid bugs from the listen(2) change. * @@ -153,7 +156,7 @@ static addr_ops *addrs[] = { &inet_ops, &un_ops, 0 }; /*----- Other persistent variables ----------------------------------------*/ -static addr_opts gao = { 0 }; +static addr_opts gsao = { 0 }, gtao = { 0 }; /*----- Parsing address types ---------------------------------------------*/ @@ -269,7 +272,7 @@ static void stept_close(endpt *e) DESTROY(ee); } -/* --- @stept_go@ --- * +/* --- @starget_connected@ --- * * * Arguments: @int fd@ = file descriptor now ready for use * @void *p@ = pointer to an endpoint structure @@ -279,7 +282,7 @@ static void stept_close(endpt *e) * Use: Handles successful connection of the target endpoint. */ -static void stept_go(int fd, void *p) +void starget_connected(int fd, void *p) { stept *e = p; @@ -288,7 +291,10 @@ static void stept_go(int fd, void *p) endpt_kill(&e->e); } else { reffd *r = reffd_init(fd); + int opt = 1; REFFD_INC(r); + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); e->e.in = e->e.out = r; e->e.f &= ~EPF_PENDING; if (e->e.other) @@ -315,7 +321,7 @@ static int ssource_option(source *s, scanner *sc) ssource *ss = (ssource *)s; ssource_opts *sso = ss ? &ss->o : &ssgo; - CONF_BEGIN(sc, "socket", "socket") + CONF_BEGIN(sc, "socket", "socket source") /* --- Make sure the next token is a word --- */ @@ -360,7 +366,7 @@ static int ssource_option(source *s, scanner *sc) if (strcmp(sc->d.buf, "logging") == 0 || strcmp(sc->d.buf, "log") == 0) { - addr_opts *ao = ss ? ss->ao : &gao; + addr_opts *ao = ss ? ss->ao : &gsao; token(sc); if (sc->t == '=') token(sc); @@ -374,12 +380,12 @@ static int ssource_option(source *s, scanner *sc) /* --- Pass the option around the various address types --- */ if (ss) { - if (ss->a->ops->option && ss->a->ops->option(sc, ss ? ss->ao : 0)) + if (ss->a->ops->option && ss->a->ops->option(sc, ss->ao, ADDR_SRC)) CONF_ACCEPT; } else { addr_ops **a; for (a = addrs; *a; a++) { - if ((*a)->option && (*a)->option(sc, 0)) + if ((*a)->option && (*a)->option(sc, 0, ADDR_GLOBAL)) CONF_ACCEPT; } } @@ -401,11 +407,11 @@ static source *ssource_read(scanner *sc) ss->s.desc = 0; ss->t = 0; ss->a = getaddr(sc, ADDR_SRC); - if (ss->a->ops->initopts) - ss->ao = ss->a->ops->initopts(); + if (ss->a->ops->initsrcopts) + ss->ao = ss->a->ops->initsrcopts(); else ss->ao = CREATE(addr_opts); - *ss->ao = gao; + *ss->ao = gsao; ss->o = ssgo; return (&ss->s); } @@ -506,39 +512,24 @@ static void ss_accept(int fd, unsigned mode, void *p) static void ss_listen(ssource *ss) { - gen_addr *ga = (gen_addr *)ss->a; int fd; + int opt = 1; if (!(ss->ao->f & ADDRF_NOLOG)) fw_log(-1, "[%s] reattaching listener", ss->s.desc); /* --- Make the socket --- */ - if ((fd = socket(ga->a.ops->pf, SOCK_STREAM, 0)) < 0) { + if ((fd = ss->a->ops->bind(ss->a, ss->ao)) < 0) { fw_log(-1, "[%s] couldn't create socket: %s", ss->s.desc, strerror(errno)); goto fail_0; } - /* --- Set it to allow address reuse --- */ - - { - int opt = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); - } - - /* --- Bind it to the right port --- */ - - if (bind(fd, &ga->sa, ga->a.sz)) { - fw_log(-1, "[%s] couldn't bind socket: %s", ss->s.desc, strerror(errno)); - goto fail_1; - } - if (ga->a.ops->bound) - ga->a.ops->bound(&ga->a, ss->ao); - /* --- Set it to listen for connections --- */ + setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); if (listen(fd, ss->o.listen)) { fw_log(-1, "[%s] couldn't listen on socket: %s", ss->s.desc, strerror(errno)); @@ -569,6 +560,7 @@ static void ssource_attach(source *s, scanner *sc, target *t) { ssource *ss = (ssource *)s; int fd; + int opt = 1; ss->t = t; @@ -586,33 +578,16 @@ static void ssource_attach(source *s, scanner *sc, target *t) /* --- Initialize the socket for listening --- */ - { - gen_addr *ga = (gen_addr *)ss->a; - - /* --- Make the socket --- */ - - if ((fd = socket(ga->a.ops->pf, SOCK_STREAM, 0)) < 0) - error(sc, "couldn't create socket: %s", strerror(errno)); - - /* --- Set it to allow address reuse --- */ + if ((fd = ss->a->ops->bind(ss->a, ss->ao)) < 0) + error(sc, "couldn't bind socket `%s': %s", ss->s.desc, strerror(errno)); - { - int opt = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); - } - - /* --- Bind it to the right port --- */ - - if (bind(fd, &ga->sa, ga->a.sz)) - error(sc, "couldn't bind to %s: %s", ss->s.desc, strerror(errno)); - if (ga->a.ops->bound) - ga->a.ops->bound(&ga->a, ss->ao); - - /* --- Set it to listen for connections --- */ + /* --- Set it to listen for connections --- */ - if (listen(fd, ss->o.listen)) - error(sc, "couldn't listen on socket: %s", strerror(errno)); + setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + if (listen(fd, ss->o.listen)) { + error(sc, "couldn't listen on socket `%s': %s", + ss->s.desc, strerror(errno)); } /* --- We're ready to go now --- */ @@ -635,8 +610,8 @@ static void ssource_destroy(source *s) if (ss->a->ops->unbind) ss->a->ops->unbind(ss->a); } - if (ss->a->ops->freeopts) - ss->a->ops->freeopts(ss->ao); + if (ss->a->ops->freesrcopts) + ss->a->ops->freesrcopts(ss->ao); else DESTROY(ss->ao); xfree(ss->s.desc); @@ -656,6 +631,27 @@ source_ops ssource_ops = { /*----- Target definition -------------------------------------------------*/ +/* --- @options@ --- */ + +static int starget_option(target *t, scanner *sc) +{ + starget *st = (starget *)t; + + CONF_BEGIN(sc, "starget", "socket target") + + /* --- Pass the option around the various address types --- */ + + if (st) { + if (st->a->ops->option && st->a->ops->option(sc, st->ao, ADDR_DEST)) + CONF_ACCEPT; + } + /* We'd have done it already if it was global */ + + /* --- Done --- */ + + CONF_END; +} + /* --- @read@ --- */ static target *starget_read(scanner *sc) @@ -667,6 +663,11 @@ static target *starget_read(scanner *sc) st = CREATE(starget); st->t.ops = &starget_ops; st->a = getaddr(sc, ADDR_DEST); + if (st->a->ops->inittargopts) + st->ao = st->a->ops->inittargopts(); + else + st->ao = CREATE(addr_opts); + *st->ao = gtao; dstr_puts(&d, "socket."); st->a->ops->print(st->a, ADDR_DEST, &d); st->t.desc = xstrdup(d.buf); @@ -688,22 +689,14 @@ static endpt *starget_create(target *t, const char *desc) { starget *st = (starget *)t; stept *e = CREATE(stept); - int fd; - gen_addr *ga = (gen_addr *)st->a; - int opt; - if ((fd = socket(st->a->ops->pf, SOCK_STREAM, 0)) < 0) - return (0); - setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); e->e.ops = &stept_ops; e->e.other = 0; e->e.f = EPF_FILE | EPF_PENDING; e->e.t = 0; e->desc = xstrdup(desc); - - if (conn_init(&e->c, sel, fd, &ga->sa, ga->a.sz, stept_go, e)) { - fw_log(-1, "[%s] connection failed: %s", e->desc, strerror(errno)); + if (st->a->ops->connect(st->a, st->ao, &e->c, &e->e)) { + fw_log(-1, "[%s] couldn't connect: %s", e->desc, strerror(errno)); DESTROY(e); return (0); } @@ -716,6 +709,10 @@ static endpt *starget_create(target *t, const char *desc) static void starget_destroy(target *t) { starget *st = (starget *)t; + if (st->a->ops->freetargopts) + st->a->ops->freetargopts(st->ao); + else + DESTROY(st->ao); st->a->ops->destroy(st->a); xfree(st->t.desc); DESTROY(st); @@ -725,7 +722,7 @@ static void starget_destroy(target *t) target_ops starget_ops = { "socket", - 0, starget_read, starget_create, starget_destroy + starget_option, starget_read, starget_create, starget_destroy }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/socket.h b/socket.h index b64bd5e..e85d455 100644 --- a/socket.h +++ b/socket.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: socket.h,v 1.1 1999/07/26 23:33:32 mdw Exp $ + * $Id: socket.h,v 1.2 2003/11/25 14:08:23 mdw Exp $ * * Socket source and target definitions * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: socket.h,v $ + * Revision 1.2 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.1 1999/07/26 23:33:32 mdw * New sources and targets. * @@ -56,6 +59,20 @@ extern source_ops ssource_ops; extern target_ops starget_ops; +/*----- Functions provided ------------------------------------------------*/ + +/* --- @starget_connected@ --- * + * + * Arguments: @int fd@ = file descriptor now ready for use + * @void *p@ = pointer to an endpoint structure + * + * Returns: --- + * + * Use: Handles successful connection of the target endpoint. + */ + +extern void starget_connected(int /*fd*/, void */*p*/); + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus diff --git a/target.h b/target.h index 5077c39..862527a 100644 --- a/target.h +++ b/target.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: target.h,v 1.1 1999/07/26 23:33:01 mdw Exp $ + * $Id: target.h,v 1.2 2003/11/25 14:08:23 mdw Exp $ * * Description of forwarding targets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: target.h,v $ + * Revision 1.2 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.1 1999/07/26 23:33:01 mdw * Infrastructure for the new design. * @@ -69,8 +72,8 @@ typedef struct target_ops { /* --- @option@ --- * * - * Arguments: @scanner *sc@ = scanner to read from - * @target *t@ = pointer to target object, or zero if global + * Arguments: @target *t@ = pointer to target object, or zero if global + * @scanner *sc@ = scanner to read from * * Returns: Nonzero to claim the option. * diff --git a/un.c b/un.c index e120f95..e415256 100644 --- a/un.c +++ b/un.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: un.c,v 1.5 2002/02/22 23:43:32 mdw Exp $ + * $Id: un.c,v 1.6 2003/11/25 14:08:23 mdw Exp $ * * Protocol specific definitions for Unix-domain sockets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: un.c,v $ + * Revision 1.6 2003/11/25 14:08:23 mdw + * Debianization. Socket target options. Internet binding. + * * Revision 1.5 2002/02/22 23:43:32 mdw * Call @xfree@ rather than @free@. * @@ -77,6 +80,7 @@ #include "fw.h" #include "reffd.h" #include "scan.h" +#include "socket.h" #include "un.h" /*----- Data structures ---------------------------------------------------*/ @@ -141,7 +145,7 @@ static addr_opts *un_initopts(void) /* --- @option@ --- */ -static int un_option(scanner *sc, addr_opts *ao) +static int srcopt(scanner *sc, addr_opts *ao) { un_opts *uo = (un_opts *)ao; CONF_BEGIN(sc, "unix", "Unix domain socket") @@ -152,6 +156,14 @@ static int un_option(scanner *sc, addr_opts *ao) CONF_END; } +static int un_option(scanner *sc, addr_opts *ao, unsigned type) +{ + CONF_BEGIN(sc, "unix", "Unix domain socket"); + if (type != ADDR_DEST && srcopt(sc, ao)) + CONF_ACCEPT; + CONF_END; +} + /* --- @accept@ --- */ static reffd *un_accept(int fd, addr_opts *ao, const char *desc) @@ -189,19 +201,26 @@ static void un_freeopts(addr_opts *ao) DESTROY(uo); } -/* --- @bound@ --- */ +/* --- @bind@ --- */ -static void un_bound(addr *a, addr_opts *ao) +static int un_bind(addr *a, addr_opts *ao) { un_addr *ua = (un_addr *)a; un_opts *uo = (un_opts *)ao; - if (fattr_apply(ua->sun.sun_path, &uo->f)) { - dstr d = DSTR_INIT; - un_print(a, ADDR_SRC, &d); - fw_log(-1, "[%s] couldn't apply file attributes: %s", - d.buf, strerror(errno)); - dstr_destroy(&d); - } + int fd; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + goto fail_0; + if (bind(fd, (struct sockaddr *)&ua->sun, sizeof(ua->sun))) + goto fail_1; + if (fattr_apply(ua->sun.sun_path, &uo->f)) + goto fail_1; + return (fd); + +fail_1: + close(fd); +fail_0: + return (-1); } /* --- @unbind@ --- */ @@ -212,12 +231,28 @@ static void un_unbind(addr *a) unlink(ua->sun.sun_path); } +/* --- @connect@ --- */ + +static int un_connect(addr *a, addr_opts *ao, conn *c, endpt *e) +{ + un_addr *ua = (un_addr *)a; + int fd; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + goto fail_0; + return (conn_init(c, sel, fd, (struct sockaddr *)&ua->sun, sizeof(ua->sun), + starget_connected, e)); +fail_0: + return (-1); +} + /* --- Protocol definition --- */ addr_ops un_ops = { - "unix", PF_UNIX, + "unix", un_read, un_destroy, un_print, - un_initopts, un_option, un_accept, un_freeopts, un_bound, un_unbind + un_initopts, un_option, un_freeopts, un_bind, un_unbind, un_accept, + 0, 0, un_connect }; /*----- That's all, folks -------------------------------------------------*/ -- 2.11.0 From 71b6cc0bc9dd7f041f486a90b158954b5c2d1948 Mon Sep 17 00:00:00 2001 From: mdw Date: Tue, 25 Nov 2003 14:11:18 +0000 Subject: [PATCH 11/16] Preliminary bump to 1.2.7. --- configure.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 446e361..51ca5b7 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl -*-m4-*- dnl -dnl $Id: configure.in,v 1.15 2003/11/25 14:08:23 mdw Exp $ +dnl $Id: configure.in,v 1.16 2003/11/25 14:11:18 mdw Exp $ dnl dnl Configuration script for fw dnl @@ -28,6 +28,9 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. dnl ----- Revision history -------------------------------------------------- dnl dnl $Log: configure.in,v $ +dnl Revision 1.16 2003/11/25 14:11:18 mdw +dnl Preliminary bump to 1.2.7. +dnl dnl Revision 1.15 2003/11/25 14:08:23 mdw dnl Debianization. Socket target options. Internet binding. dnl @@ -61,7 +64,7 @@ dnl Initial revision. dnl AC_INIT(fw.c) -AM_INIT_AUTOMAKE(fw, 1.2.6) +AM_INIT_AUTOMAKE(fw, 1.2.7) AM_CONFIG_HEADER(config.h) AC_PROG_CC -- 2.11.0 From 1c2054c7558f523dec9d7c1f243a2ceddd81c781 Mon Sep 17 00:00:00 2001 From: mdw Date: Tue, 25 Nov 2003 14:46:50 +0000 Subject: [PATCH 12/16] Update docco for new options. --- debian/rules | 2 +- fw.1 | 66 +++++++++++++++++++++++++++++++----- fw.c | 108 +++++++++++++++++++++++++++++++---------------------------- grammar | 105 ++++++++++++++++++++++++++++++--------------------------- 4 files changed, 170 insertions(+), 111 deletions(-) diff --git a/debian/rules b/debian/rules index d592b5b..3970631 100755 --- a/debian/rules +++ b/debian/rules @@ -23,7 +23,7 @@ binary-arch: install dh_testdir -a dh_testroot -a dh_compress -a - dh_installdocs -a + dh_installdocs -a grammar dh_strip -a dh_shlibdeps -a dh_gencontrol -a diff --git a/fw.1 b/fw.1 index 4419f14..251aa5a 100644 --- a/fw.1 +++ b/fw.1 @@ -1,6 +1,6 @@ .\" -*-nroff-*- .\" -.\" $Id: fw.1,v 1.15 2003/01/24 20:13:04 mdw Exp $ +.\" $Id: fw.1,v 1.16 2003/11/25 14:46:50 mdw Exp $ .\" .\" Manual page for fw .\" @@ -28,6 +28,9 @@ .\" ---- Revision history --------------------------------------------------- .\" .\" $Log: fw.1,v $ +.\" Revision 1.16 2003/11/25 14:46:50 mdw +.\" Update docco for new options. +.\" .\" Revision 1.15 2003/01/24 20:13:04 mdw .\" Fix bogus examples. Explain quoting rules for `exec' endpoints. .\" @@ -1077,11 +1080,23 @@ The .B inet source address accepts the following options: .OS "Socket options" -.BR socket.inet. [ allow | deny ] -.RB [ from ] -.I address +.B socket.inet.source.addr +.RB [ = ] +.RR any | \c +.I addr +.OD +Specify the IP address on which to listen for incoming connections. The +default is +.BR any , +which means to listen on all addresses, though it may be useful to +specify this explicitly, if the global setting is different. +.OE +.OS "Socket options" +.BR socket.inet.source. [ allow | deny ] +.RB [ host ] +.I addr .RB [ / -.IR address ] +.IR addr ] .OD Adds an entry to the source's access control list. If only one .I address @@ -1094,6 +1109,26 @@ and mean the same), and the entry applies to any address which, when masked by the netmask, is equal to the masked network address. .OE +.OS "Socket options" +.BR socket.inet.source. [ allow | deny ] +.B priv-port +.OD +Accept or reject connections from low-numbered `privileged' ports, in +the range 0--1023. +.OE +.OS "Socket options" +.B socket.inet.dest.addr +.RB [ = ] +.RR any | \c +.I addr +.OD +Specify the IP address to bind the local socket to when making an +outbound connection. The default is +.BR any , +which means to use whichever address the kernel thinks is most +convenient. This option is useful if the destination is doing +host-based access control and your server is multi-homed. +.OE .PP The access control rules are examined in the order: local entries first, then global ones, each in the order given in the configuration file. @@ -1502,11 +1537,24 @@ exec .RB [ = ] .BR yes | no .PP -.BR socket.inet. [ allow | deny ] -.RB [ from ] -.I address +.BR socket.inet.source. [ allow | deny ] +.RB [ host ] +.I addr .RB [ / -.IR address ] +.IR addr ] +.br +.BR socket.inet.source. [ allow | deny ] +.B priv-port +.br +.B socket.inet.source.addr +.RB [ = ] +.BR any | \c +.I addr +.br +.B socket.inet.dest.addr +.RB [ = ] +.BR any | \c +.I addr .PP .BR socket.unix.fattr. * . diff --git a/fw.c b/fw.c index b0eed70..5a5db0f 100644 --- a/fw.c +++ b/fw.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: fw.c,v 1.14 2003/01/24 20:12:40 mdw Exp $ + * $Id: fw.c,v 1.15 2003/11/25 14:46:50 mdw Exp $ * * Port forwarding thingy * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: fw.c,v $ + * Revision 1.15 2003/11/25 14:46:50 mdw + * Update docco for new options. + * * Revision 1.14 2003/01/24 20:12:40 mdw * Correctly cast uid and gid sentinel values. * @@ -515,53 +518,53 @@ static void grammar(FILE *fp) Grammar summary\n\ \n\ Basic syntax\n\ - file ::= empty | file stmt [`;']\n\ - stmt ::= option-stmt | fw-stmt\n\ - fw-stmt ::= `fw' source options [`to'|`->'] target options\n\ - options ::= `{' option-seq `}'\n\ - option-seq ::= empty | option-stmt [`;'] option-seq\n\ + FILE ::= EMPTY | FILE STMT [`;']\n\ + STMT ::= OPTION-STMT | FW-STMT\n\ + FW-STMT ::= `fw' SOURCE OPTIONS [`to'|`->'] TARGET OPTIONS\n\ + OPTIONS ::= `{' OPTION-SEQ `}'\n\ + OPTION-SEQ ::= EMPTY | OPTION-STMT [`;'] OPTION-SEQ\n\ \n\ Option syntax\n\ - option-stmt ::= q-option\n\ - q-option ::= option\n\ - | prefix `.' q-option\n\ - | prefix `{' option-seq `}'\n\ - prefix ::= word\n\ + OPTION-STMT ::= Q-OPTION\n\ + Q-OPTION ::= OPTION\n\ + | PREFIX `.' Q-OPTION\n\ + | PREFIX `{' OPTION-SEQ `}'\n\ + PREFIX ::= WORD\n\ \n\ File source and target\n\ - source ::= file\n\ - target ::= file\n\ - file ::= `file' [`.'] fspec [`,' fspec]\n\ - fspec ::= fd-spec | name-spec | null-spec\n\ - fd-spec ::= [[`:']`fd'[`:']] number|`stdin'|`stdout'\n\ - name-spec ::= [[`:']`file'[`:']] file-name\n\ - file-name ::= path-seq | [ path-seq ]\n\ - path-seq ::= path-elt | path-seq path-elt\n\ - path-elt ::= `/' | word\n\ - null-spec ::= [`:']`null'[`:']\n\ + SOURCE ::= FILE\n\ + TARGET ::= FILE\n\ + FILE ::= `file' [`.'] FSPEC [`,' FSPEC]\n\ + FSPEC ::= FD-SPEC | NAME-SPEC | NULL-SPEC\n\ + FD-SPEC ::= [[`:']`fd'[`:']] NUMBER|`stdin'|`stdout'\n\ + NAME-SPEC ::= [[`:']`file'[`:']] FILE-NAME\n\ + FILE-NAME ::= PATH-SEQ | [ PATH-SEQ ]\n\ + PATH-SEQ ::= PATH-ELT | PATH-SEQ PATH-ELT\n\ + PATH-ELT ::= `/' | WORD\n\ + NULL-SPEC ::= [`:']`null'[`:']\n\ \n\ Exec source and target\n\ - source ::= exec\n\ - target ::= exec\n\ - exec ::= `exec' [`.'] cmd-spec\n\ - cmd-spec ::= shell-cmd | [prog-name] `[' argv0 arg-seq `]'\n\ - arg-seq ::= word | arg-seq word\n\ - shell-cmd ::= word\n\ - argv0 ::= word\n\ + SOURCE ::= EXEC\n\ + TARGET ::= EXEC\n\ + EXEC ::= `exec' [`.'] CMD-SPEC\n\ + CMD-SPEC ::= SHELL-CMD | [PROG-NAME] `[' ARGV0 ARG-SEQ `]'\n\ + ARG-SEQ ::= WORD | ARG-SEQ WORD\n\ + SHELL-CMD ::= WORD\n\ + ARGV0 ::= WORD\n\ \n\ Socket source and target\n\ - source ::= socket-source\n\ - target ::= socket-target\n\ - socket-source ::= [`socket'[`.']] [[`:']addr-type[`:']] source-addr\n\ - socket-target ::= [`socket'[`.']] [[`:']addr-type[`:']] target-addr\n\ + SOURCE ::= SOCKET-SOURCE\n\ + TARGET ::= SOCKET-TARGET\n\ + SOCKET-SOURCE ::= [`socket'[`.']] [[`:']ADDR-TYPE[`:']] SOURCE-ADDR\n\ + SOCKET-TARGET ::= [`socket'[`.']] [[`:']ADDR-TYPE[`:']] TARGET-ADDR\n\ \n\ - inet-source-addr ::= [port] port\n\ - inet-target-addr ::= address [`:'] port\n\ - address ::= addr-elt | address addr-elt\n\ - addr-elt ::= `.' | word\n\ + INET-SOURCE-ADDR ::= [`port'] PORT\n\ + INET-TARGET-ADDR ::= ADDRESS [`:'] PORT\n\ + ADDRESS ::= ADDR-ELT | ADDRESS ADDR-ELT\n\ + ADDR-ELT ::= `.' | WORD\n\ \n\ - unix-source-addr ::= file-name\n\ - unix-target-addr ::= file-name\n\ + UNIX-SOURCE-ADDR ::= FILE-NAME\n\ + UNIX-TARGET-ADDR ::= FILE-NAME\n\ "); } @@ -572,9 +575,9 @@ static void options(FILE *fp) Options summary\n\ \n\ File attributes (`fattr')\n\ - prefix.fattr.mode [=] mode\n\ - prefix.fattr.owner [=] user\n\ - prefix.fattr.group [=] group\n\ + prefix.FATTR.MODE [=] MODE\n\ + prefix.FATTR.OWNER [=] USER\n\ + prefix.FATTR.GROUP [=] GROUP\n\ \n\ File options\n\ file.create [=] yes|no\n\ @@ -583,21 +586,24 @@ File options\n\ \n\ Exec options\n\ exec.logging [=] yes|no\n\ - exec.dir [=] file-name\n\ - exec.root [=] file-name\n\ - exec.user [=] user\n\ - exec.group [=] group\n\ - exec.rlimit.limit[.hard|.soft] [=] value\n\ + exec.dir [=] FILE-NAME\n\ + exec.root [=] FILE-NAME\n\ + exec.user [=] USER\n\ + exec.group [=] GROUP\n\ + exec.rlimit.LIMIT[.hard|.soft] [=] VALUE\n\ exec.env.clear\n\ - exec.env.unset var\n\ - exec.env.[set] var [=] value\n\ + exec.env.unset VAR\n\ + exec.env.[set] VAR [=] VALUE\n\ \n\ Socket options\n\ - socket.conn [=] number|unlimited|one-shot\n\ - socket.listen [=] number\n\ + socket.conn [=] NUMBER|unlimited|one-shot\n\ + socket.listen [=] NUMBER\n\ socket.logging [=] yes|no\n\ \n\ - socket.inet.[allow|deny] [from] address [/ address]\n\ + socket.inet.source.[allow|deny] [host] ADDR [/ ADDR]\n\ + socket.inet.source.[allow|deny] priv-port\n\ + socket.inet.source.addr [=] any|ADDR\n\ + socket.inet.dest.addr [=] any|ADDR\n\ \n\ socket.unix.fattr.*\n\ "); diff --git a/grammar b/grammar index ae3ce1f..6c4fc02 100644 --- a/grammar +++ b/grammar @@ -1,56 +1,56 @@ Basic syntax - file ::= empty | file stmt [`;'] - stmt ::= option-stmt | fw-stmt - fw-stmt ::= `fw' source options [`to'|`->'] target options - options ::= `{' option-seq `}' - option-seq ::= empty | option-stmt [`;'] option-seq + FILE ::= EMPTY | FILE STMT [`;'] + STMT ::= OPTION-STMT | FW-STMT + FW-STMT ::= `fw' SOURCE OPTIONS [`to'|`->'] TARGET OPTIONS + OPTIONS ::= `{' OPTION-SEQ `}' + OPTION-SEQ ::= EMPTY | OPTION-STMT [`;'] OPTION-SEQ Option syntax - option-stmt ::= q-option - q-option ::= option - | prefix `.' q-option - | prefix `{' option-seq `}' - prefix ::= word + OPTION-STMT ::= Q-OPTION + Q-OPTION ::= OPTION + | PREFIX `.' Q-OPTION + | PREFIX `{' OPTION-SEQ `}' + PREFIX ::= WORD File source and target - source ::= file - target ::= file - file ::= `file' [`.'] fspec [`,' fspec] - fspec ::= fd-spec | name-spec | null-spec - fd-spec ::= [[`:']`fd'[`:']] number|`stdin'|`stdout' - name-spec ::= [[`:']`file'[`:']] file-name - file-name ::= path-seq | [ path-seq ] - path-seq ::= path-elt | path-seq path-elt - path-elt ::= `/' | word - null-spec ::= [`:']`null'[`:'] + SOURCE ::= FILE + TARGET ::= FILE + FILE ::= `file' [`.'] FSPEC [`,' FSPEC] + FSPEC ::= FD-SPEC | NAME-SPEC | NULL-SPEC + FD-SPEC ::= [[`:']`fd'[`:']] NUMBER|`stdin'|`stdout' + NAME-SPEC ::= [[`:']`file'[`:']] FILE-NAME + FILE-NAME ::= PATH-SEQ | [ PATH-SEQ ] + PATH-SEQ ::= PATH-ELT | PATH-SEQ PATH-ELT + PATH-ELT ::= `/' | WORD + NULL-SPEC ::= [`:']`null'[`:'] Exec source and target - source ::= exec - target ::= exec - exec ::= `exec' [`.'] cmd-spec - cmd-spec ::= shell-cmd | [prog-name] `[' argv0 arg-seq `]' - arg-seq ::= word | arg-seq word - shell-cmd ::= word - argv0 ::= word + SOURCE ::= EXEC + TARGET ::= EXEC + EXEC ::= `exec' [`.'] CMD-SPEC + CMD-SPEC ::= SHELL-CMD | [PROG-NAME] `[' ARGV0 ARG-SEQ `]' + ARG-SEQ ::= WORD | ARG-SEQ WORD + SHELL-CMD ::= WORD + ARGV0 ::= WORD Socket source and target - source ::= socket-source - target ::= socket-target - socket-source ::= [`socket'[`.']] [[`:']addr-type[`:']] source-addr - socket-target ::= [`socket'[`.']] [[`:']addr-type[`:']] target-addr + SOURCE ::= SOCKET-SOURCE + TARGET ::= SOCKET-TARGET + SOCKET-SOURCE ::= [`socket'[`.']] [[`:']ADDR-TYPE[`:']] SOURCE-ADDR + SOCKET-TARGET ::= [`socket'[`.']] [[`:']ADDR-TYPE[`:']] TARGET-ADDR - inet-source-addr ::= [port] port - inet-target-addr ::= address [`:'] port - address ::= addr-elt | address addr-elt - addr-elt ::= `.' | word + INET-SOURCE-ADDR ::= [`port'] PORT + INET-TARGET-ADDR ::= ADDRESS [`:'] PORT + ADDRESS ::= ADDR-ELT | ADDRESS ADDR-ELT + ADDR-ELT ::= `.' | WORD - unix-source-addr ::= file-name - unix-target-addr ::= file-name + UNIX-SOURCE-ADDR ::= FILE-NAME + UNIX-TARGET-ADDR ::= FILE-NAME File attributes (`fattr') - prefix.fattr.mode [=] mode - prefix.fattr.owner [=] user - prefix.fattr.group [=] group + PREFIX.fattr.mode [=] MODE + PREFIX.fattr.owner [=] USER + PREFIX.fattr.group [=] GROUP File options file.create [=] yes|no @@ -59,17 +59,22 @@ File options Exec options exec.logging [=] yes|no - exec.dir [=] file-name - exec.root [=] file-name - exec.user [=] user - exec.group [=] group - exec.rlimit.limit[.hard|.soft] [=] value + exec.dir [=] FILE-NAME + exec.root [=] FILE-NAME + exec.user [=] USER + exec.group [=] GROUP + exec.rlimit.LIMIT[.hard|.soft] [=] VALUE exec.env.clear - exec.env.unset var - exec.env.[set] var [=] value + exec.env.unset VAR + exec.env.[set] VAR [=] VALUE Socket options - socket.conn [=] number|unlimited|one-shot + socket.conn [=] NUMBER|unlimited|one-shot socket.logging [=] yes|no - socket.inet.[allow|deny] [from] address [/ address] - socket.unix.fattr.* + + socket.inet.source.[allow|deny] priv-port + socket.inet.source.[allow|deny] [host] ADDR [/ ADDR] + socket.inet.source.addr [=] any|ADDR + socket.inet.dest.addr [=] any|ADDR + + socket.unix.source.fattr.* -- 2.11.0 From ee599f5566c155b4decd9c77bfa4d6212f20891e Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 29 Nov 2003 20:36:07 +0000 Subject: [PATCH 13/16] Privileged outgoing connections. --- Makefile.am | 9 +- addr.h | 19 ++- debian/changelog | 11 +- debian/control | 2 +- exec.c | 7 +- file.c | 7 +- fw.1 | 39 +++++- fw.c | 11 +- grammar | 1 + identify.c | 10 +- inet.c | 46 ++++++- privconn.c | 380 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ privconn.h | 102 +++++++++++++++ socket.c | 33 +++-- target.h | 16 ++- un.c | 7 +- 16 files changed, 665 insertions(+), 35 deletions(-) create mode 100644 privconn.c create mode 100644 privconn.h diff --git a/Makefile.am b/Makefile.am index c9598c6..2889c16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## -*-makefile-*- ## -## $Id: Makefile.am,v 1.6 2003/11/25 14:08:23 mdw Exp $ +## $Id: Makefile.am,v 1.7 2003/11/29 20:36:07 mdw Exp $ ## ## Makefile for fw ## @@ -28,6 +28,9 @@ ##----- Revision history ---------------------------------------------------- ## ## $Log: Makefile.am,v $ +## Revision 1.7 2003/11/29 20:36:07 mdw +## Privileged outgoing connections. +## ## Revision 1.6 2003/11/25 14:08:23 mdw ## Debianization. Socket target options. Internet binding. ## @@ -68,7 +71,7 @@ fw_SOURCES = \ inet.c un.c \ inet.h un.h \ \ - acl.c fattr.c identify.c \ - acl.h fattr.h identify.h rlimits.h + acl.c fattr.c identify.c privconn.c \ + acl.h fattr.h identify.h privconn.h rlimits.h ##----- That's all, folks --------------------------------------------------- diff --git a/addr.h b/addr.h index adc4cd1..6b16c52 100644 --- a/addr.h +++ b/addr.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: addr.h,v 1.3 2003/11/25 14:08:23 mdw Exp $ + * $Id: addr.h,v 1.4 2003/11/29 20:36:07 mdw Exp $ * * Generic interface to network address handlers * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: addr.h,v $ + * Revision 1.4 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.3 2003/11/25 14:08:23 mdw * Debianization. Socket target options. Internet binding. * @@ -174,6 +177,20 @@ typedef struct addr_ops { int (*option)(scanner */*sc*/, addr_opts */*ao*/, unsigned /*type*/); + /* --- @confirm@ --- * + * + * Arguments: @addr *a@ = pointer to an address structure + * @unsigned type@ = kind of address this is + * @addr_opts *ao@ = address options + * + * Returns: --- + * + * Use: Called during initialization when an address is fully + * configured. + */ + + void (*confirm)(addr */*a*/, unsigned /*type*/, addr_opts */*ao*/); + /* --- @freesrcopts@ --- * * * Arguments: @addr_opts *ao@ = data block to remove diff --git a/debian/changelog b/debian/changelog index edbda91..87c21a9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,9 +3,12 @@ fw (1.2.7) experimental; urgency=low * Debianization! * Fix data corruption in chan.c. - - * Socket target option support. Currently there's just bind address. - + * Support binding to specific addresses for inet sources and targets. - -- Mark Wooding Tue, 25 Nov 2003 14:07:42 +0000 + * Require (or prevent) privileged incoming connections in ACLs. + + * Privileged outgoing connections, if started as root, with privilege + separation if requested to drop privileges after initialization. + + -- Mark Wooding Sat, 29 Nov 2003 20:35:40 +0000 diff --git a/debian/control b/debian/control index d0a1a28..c462e17 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,7 @@ Source: fw Section: net Priority: extra -Build-Depends: mlib-dev (>= 2.0.2), debhelper (>= 4.0.2) +Build-Depends: mlib-dev (>= 2.0.3), debhelper (>= 4.0.2) Maintainer: Mark Wooding Standards-Version: 3.1.1 diff --git a/exec.c b/exec.c index 54a6547..60d1785 100644 --- a/exec.c +++ b/exec.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: exec.c,v 1.7 2003/01/24 20:12:26 mdw Exp $ + * $Id: exec.c,v 1.8 2003/11/29 20:36:07 mdw Exp $ * * Source and target for executable programs * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: exec.c,v $ + * Revision 1.8 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.7 2003/01/24 20:12:26 mdw * Correctly cast uid and gid sentinel values. Parse full filenames in * exec arguments (can't do it for program, unfortunately, since the die is @@ -1195,7 +1198,7 @@ static void xtarget_destroy(target *t) target_ops xtarget_ops = { "exec", - xtarget_option, xtarget_read, xtarget_create, xtarget_destroy + xtarget_option, xtarget_read, 0, xtarget_create, xtarget_destroy }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/file.c b/file.c index 7c78645..371273e 100644 --- a/file.c +++ b/file.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: file.c,v 1.5 2002/02/22 23:43:32 mdw Exp $ + * $Id: file.c,v 1.6 2003/11/29 20:36:07 mdw Exp $ * * File source and target * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: file.c,v $ + * Revision 1.6 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.5 2002/02/22 23:43:32 mdw * Call @xfree@ rather than @free@. * @@ -615,7 +618,7 @@ static void ftarget_destroy(target *t) target_ops ftarget_ops = { "file", - ftarget_option, ftarget_read, ftarget_create, ftarget_destroy + ftarget_option, ftarget_read, 0, ftarget_create, ftarget_destroy }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/fw.1 b/fw.1 index 251aa5a..d90d9d9 100644 --- a/fw.1 +++ b/fw.1 @@ -1,6 +1,6 @@ .\" -*-nroff-*- .\" -.\" $Id: fw.1,v 1.16 2003/11/25 14:46:50 mdw Exp $ +.\" $Id: fw.1,v 1.17 2003/11/29 20:36:07 mdw Exp $ .\" .\" Manual page for fw .\" @@ -28,6 +28,9 @@ .\" ---- Revision history --------------------------------------------------- .\" .\" $Log: fw.1,v $ +.\" Revision 1.17 2003/11/29 20:36:07 mdw +.\" Privileged outgoing connections. +.\" .\" Revision 1.16 2003/11/25 14:46:50 mdw .\" Update docco for new options. .\" @@ -1129,6 +1132,36 @@ which means to use whichever address the kernel thinks is most convenient. This option is useful if the destination is doing host-based access control and your server is multi-homed. .OE +.OS "Socket options" +.B socket.inet.dest.priv-port +.RB [=] +.BR yes | no +.OD +Make a privileged connection (i.e., from a low-numbered port) to the +target. This only works if +.B fw +was started with root privileges. However, it still works if +.B fw +has +.I dropped +privileges after initialization (the +.B \-s +option). Before dropping privileges, +.B fw +forks off a separate process which continues to run with root +privileges, and on demand passes sockets bound to privileged ports and +connected to the appropriate peer back to the main program. The +privileged child only passes back sockets connected to peer addresses +named in the configuration; even if the +.B fw +process is compromised, it can't make privileged connections to other +addresses. Note that because of this privilege separation, it's also +not possible to reconfigure +.B fw +to make privileged connections to different peer addresses later. by +changing configuration files and sending the daemon a +.BR SIGHUP . +.OE .PP The access control rules are examined in the order: local entries first, then global ones, each in the order given in the configuration file. @@ -1555,6 +1588,10 @@ exec .RB [ = ] .BR any | \c .I addr +.br +.B socket.inet.dest.priv-port +.RB [=] +.BR yes | no .PP .BR socket.unix.fattr. * . diff --git a/fw.c b/fw.c index 5a5db0f..2dec3c0 100644 --- a/fw.c +++ b/fw.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: fw.c,v 1.15 2003/11/25 14:46:50 mdw Exp $ + * $Id: fw.c,v 1.16 2003/11/29 20:36:07 mdw Exp $ * * Port forwarding thingy * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: fw.c,v $ + * Revision 1.16 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.15 2003/11/25 14:46:50 mdw * Update docco for new options. * @@ -115,6 +118,7 @@ #include "fattr.h" #include "file.h" #include "fw.h" +#include "privconn.h" #include "scan.h" #include "socket.h" #include "source.h" @@ -247,6 +251,8 @@ void parse(scanner *sc) /* --- Combine the source and target --- */ s->ops->attach(s, sc, t); + if (t->ops->confirm) + t->ops->confirm(t); } /* --- Include configuration from a file --- * @@ -604,6 +610,7 @@ Socket options\n\ socket.inet.source.[allow|deny] priv-port\n\ socket.inet.source.addr [=] any|ADDR\n\ socket.inet.dest.addr [=] any|ADDR\n\ + socket.inet.dest.priv-port [=] yes|no\n\ \n\ socket.unix.fattr.*\n\ "); @@ -805,6 +812,8 @@ int main(int argc, char *argv[]) /* --- Drop privileges --- */ + if (drop != (uid_t)-1) + privconn_split(sel); #ifdef HAVE_SETGROUPS if ((dropg != (gid_t)-1 && (setgid(dropg) || setgroups(1, &dropg))) || (drop != (uid_t)-1 && setuid(drop))) diff --git a/grammar b/grammar index 6c4fc02..02b5b16 100644 --- a/grammar +++ b/grammar @@ -76,5 +76,6 @@ Socket options socket.inet.source.[allow|deny] [host] ADDR [/ ADDR] socket.inet.source.addr [=] any|ADDR socket.inet.dest.addr [=] any|ADDR + oscket.inet.dest.priv-port [=] yes|no socket.unix.source.fattr.* diff --git a/identify.c b/identify.c index 265c071..f94cc0e 100644 --- a/identify.c +++ b/identify.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: identify.c,v 1.7 2002/02/22 23:43:32 mdw Exp $ + * $Id: identify.c,v 1.8 2003/11/29 20:36:07 mdw Exp $ * * Identifies and logs the client of a connection * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: identify.c,v $ + * Revision 1.8 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.7 2002/02/22 23:43:32 mdw * Call @xfree@ rather than @free@. * @@ -133,9 +136,10 @@ static void id_done(id *i) /* --- Report the final result --- */ - fw_log(i->when, "[%s] %s from %s@%s [%s]", + fw_log(i->when, "[%s] %s from %s@%s [%s:%u]", i->q.desc, i->q.act, - i->user, i->host, inet_ntoa(i->q.rsin.sin_addr)); + i->user, i->host, + inet_ntoa(i->q.rsin.sin_addr), (unsigned)ntohs(i->q.rsin.sin_port)); /* --- Dispose of the block --- */ diff --git a/inet.c b/inet.c index 70e5c90..3a4dbd5 100644 --- a/inet.c +++ b/inet.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: inet.c,v 1.5 2003/11/25 14:08:23 mdw Exp $ + * $Id: inet.c,v 1.6 2003/11/29 20:36:07 mdw Exp $ * * Protocol specific definitions for IPv4 sockets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: inet.c,v $ + * Revision 1.6 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.5 2003/11/25 14:08:23 mdw * Debianization. Socket target options. Internet binding. * @@ -77,6 +80,7 @@ #include "fw.h" #include "identify.h" #include "inet.h" +#include "privconn.h" #include "reffd.h" #include "scan.h" #include "socket.h" @@ -101,8 +105,11 @@ typedef struct inet_srcopts { typedef struct inet_targopts { inet_opts io; + int ipriv; } inet_targopts; +#define ADDRF_PRIVCONN 16u + static inet_srcopts inet_globalsrc = { { { 0 }, { INADDR_ANY } }, 0, &inet_globalsrc.acl }; static inet_targopts inet_globaltarg = @@ -201,6 +208,7 @@ static addr_opts *inet_inittargopts(void) { inet_targopts *io = CREATE(inet_targopts); *io = inet_globaltarg; + io->ipriv = -1; return (&io->io.ao); } @@ -261,7 +269,8 @@ static int srcopt(scanner *sc, addr_opts *ao) if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "from") == 0) token(sc); - if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "priv-port") == 0) { + if (sc->t == CTOK_WORD && (strcmp(sc->d.buf, "priv") == 0 || + strcmp(sc->d.buf, "priv-port") == 0)) { acl_addpriv(&io->acltail, act); token(sc); } else { @@ -327,6 +336,16 @@ static int targopt(scanner *sc, addr_opts *ao) addropt(sc, &io->io); CONF_ACCEPT; } + if (strcmp(sc->d.buf, "priv") == 0 || + strcmp(sc->d.buf, "priv-port") == 0) { + token(sc); + if (sc->t == '=') token(sc); + if (conf_enum(sc, "no,yes", ENUM_ABBREV, "privileged connection status")) + io->io.ao.f |= ADDRF_PRIVCONN; + else + io->io.ao.f &= ~ADDRF_PRIVCONN; + CONF_ACCEPT; + } CONF_END; } @@ -340,6 +359,23 @@ static int inet_option(scanner *sc, addr_opts *ao, unsigned type) CONF_END; } +/* --- @confirm@ --- */ + +static void inet_confirm(addr *a, unsigned type, addr_opts *ao) +{ + inet_addrx *ia = (inet_addrx *)a; + + switch (type) { + case ADDR_DEST: { + inet_targopts *io = (inet_targopts *)ao; + if ((io->io.ao.f & ADDRF_PRIVCONN) && + (io->ipriv = privconn_adddest(ia->sin.sin_addr, + ia->sin.sin_port)) < 0) + die(1, "couldn't add privileged connection target (too late)"); + } break; + } +} + /* --- @freeopts@ --- */ static void inet_freesrcopts(addr_opts *ao) @@ -431,6 +467,10 @@ static int inet_connect(addr *a, addr_opts *ao, conn *c, endpt *e) inet_targopts *io = (inet_targopts *)ao; int fd; + if (io->ipriv >= 0) { + return (privconn_connect(c, sel, io->ipriv, io->io.bind, + starget_connected, e)); + } if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) goto fail_0; if (io->io.bind.s_addr != INADDR_ANY) { @@ -456,7 +496,7 @@ fail_0: addr_ops inet_ops = { "inet", inet_read, inet_destroy, inet_print, - inet_initsrcopts, inet_option, inet_freesrcopts, + inet_initsrcopts, inet_option, inet_confirm, inet_freesrcopts, inet_bind, 0, inet_accept, inet_inittargopts, inet_freetargopts, inet_connect diff --git a/privconn.c b/privconn.c new file mode 100644 index 0000000..fcd292b --- /dev/null +++ b/privconn.c @@ -0,0 +1,380 @@ +/* -*-c-*- + * + * $Id: privconn.c,v 1.1 2003/11/29 20:36:07 mdw Exp $ + * + * Making privileged connections + * + * (c) 2003 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the `fw' port forwarder. + * + * `fw' 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. + * + * `fw' 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 `fw'; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: privconn.c,v $ + * Revision 1.1 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "privconn.h" + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct connrec { + struct in_addr peer; + unsigned port; +} connrec; + +typedef struct connrq { + int i; + struct in_addr bind; +} connrq; + +DA_DECL(connrec_v, connrec); + +/*----- Static variables --------------------------------------------------*/ + +static connrec_v cv = DA_INIT; +static conn *qhead = 0, **qtail = &qhead; +static int kidfd = -1; +static sel_file sf; + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @doconn@ --- * + * + * Arguments: @const connrq *rq@ = index of connection record + * + * Returns: Connected file descriptor, or @-1@. + * + * Use: Main privileged connection thing. + */ + +static int doconn(const connrq *rq) +{ + struct sockaddr_in sin_bind; + struct sockaddr_in sin_peer; + int fd; + int i; + connrec *c; + + /* --- Check the argument --- */ + + if (rq->i < 0 || rq->i >= DA_LEN(&cv)) { + errno = EINVAL; + goto fail_0; + } + c = &DA(&cv)[rq->i]; + + /* --- Make a new socket --- */ + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) + goto fail_0; + + /* --- Bind it to a low-numbered port --- */ + + memset(&sin_bind, 0, sizeof(sin_bind)); + sin_bind.sin_family = AF_INET; + sin_bind.sin_addr = rq->bind; + for (i = 1023; i >= 512; i--) { + sin_bind.sin_port = htons(i); + if (!bind(fd, (struct sockaddr *)&sin_bind, sizeof(sin_bind))) + goto bound; + if (errno != EADDRINUSE) + goto fail_1; + } + goto fail_1; + + /* --- Connect to the peer --- * + * + * We can find out whether it's connected later, so there's no need to + * distinguish these cases. + */ + +bound: + memset(&sin_peer, 0, sizeof(sin_peer)); + sin_peer.sin_family = AF_INET; + sin_peer.sin_addr = c->peer; + sin_peer.sin_port = c->port; + fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0); + if (connect(fd, (struct sockaddr *)&sin_peer, sizeof(sin_peer)) < 0 && + errno != EINPROGRESS) + goto fail_1; + return (fd); + + /* --- Tidy up on errors --- */ + +fail_1: + close(fd); +fail_0: + return (-1); +} + +/* --- @dochild@ --- * + * + * Arguments: @int fd@ = my file descriptor + * + * Returns: Never. + * + * Use: Child process for making privileged connections, separated + * from main process after initialization. + */ + +static void dochild(int fd) +{ + int i; + connrq rq; + int nfd; + ssize_t sz; +#if defined(_SC_OPEN_MAX) + int maxfd = sysconf(_SC_OPEN_MAX); +#elif defined(OPEN_MAX) + int maxfd = OPEN_MAX; +#else + int maxfd = -1; +#endif + struct sigaction sa; + struct sigaction sa_dfl; + + /* --- Clear out unnecessary file descriptors --- */ + + if (maxfd < 0) + maxfd = 256; + for (i = 3; i < maxfd; i++) + if (i != fd) close(i); + + /* --- Close off signal handlers --- */ + + sa_dfl.sa_handler = SIG_DFL; + sigemptyset(&sa_dfl.sa_mask); + sa_dfl.sa_flags = 0; + for (i = 0; i < 256; i++) { + if (sigaction(i, 0, &sa)) + break; + if (sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) + sigaction(i, &sa_dfl, 0); + } + + /* --- Main loop --- */ + + for (;;) { + sz = read(fd, &rq, sizeof(rq)); + if (!sz) + break; + if (sz < 0) + die(1, "read error in privconn child: %s", strerror(errno)); + if ((nfd = doconn(&rq)) < 0) + goto err; + i = 0; + sz = fdpass_send(fd, nfd, &i, sizeof(i)); + if (sz < 0) + goto err; + if (sz < sizeof(i)) + die(1, "short write in privconn child"); + continue; + + err: + if (write(fd, &errno, sizeof(errno)) < 0) + die(1, "write error in privconn child: %s", strerror(errno)); + } + _exit(0); +} + +/* --- @dorecvfd@ --- * + * + * Arguments: @int fd@ = file descriptor (@== kidfd@) + * @unsigned mode@ = what's happening (@== SEL_READ@) + * @void *p@ = uninteresting (@== 0@) + * + * Returns: --- + * + * Use: Receives a file descriptor from the privileged part. + */ + +void dorecvfd(int fd, unsigned mode, void *p) +{ + conn *c, *cc; + ssize_t n; + int e; + + n = fdpass_recv(kidfd, &fd, &e, sizeof(e)); + if (!n) + goto close; + assert(qhead); + c = qhead; + qhead = (conn *)c->writer.next; + if (!qhead) qtail = &qhead; + if (n < 0 || (errno = e) != 0) + goto fail; + if (fd == -1) { + errno = EIO; + goto fail; + } + conn_fd(c, c->writer.s, fd, c->func, c->p); + return; + +fail: + c->func(-1, c->p); + return; + +close: + close(kidfd); + kidfd = 0; + errno = EIO; + sel_rmfile(&sf); + for (c = qhead; c; c = cc) { + cc = (conn *)c->writer.next; + c->func(-1, c->p); + } + qhead = 0; + qtail = &qhead; + return; +} + +/* --- @privconn_split@ --- * + * + * Arguments: @sel_state *s@ = select state + * + * Returns: --- + * + * Use: Splits off the privileged binding code into a separate + * process. + */ + +void privconn_split(sel_state *s) +{ + pid_t kid; + int fd[2]; + + if (kidfd != -1) + return; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0) + die(1, "couldn't create privconn socketpair: %s", strerror(errno)); + kidfd = fd[0]; + if ((kid = fork()) < 0) + die(1, "couldn't fork privconn child: %s", strerror(errno)); + if (!kid) { + close(kidfd); + dochild(fd[1]); + _exit(127); + } + close(fd[1]); + fdflags(kidfd, 0, 0, FD_CLOEXEC, FD_CLOEXEC); + sel_initfile(s, &sf, kidfd, SEL_READ, dorecvfd, 0); + sel_addfile(&sf); +} + +/* --- @privconn_adddest@ --- * + * + * Arguments: @struct in_addr peer@ = address to connect to + * @unsigned port@ = port to connect to + * + * Returns: Index for this destination address, or @-1@ if not + * available. + * + * Use: Adds a valid destination for a privileged connection. + */ + +int privconn_adddest(struct in_addr peer, unsigned port) +{ + int i; + struct connrec *c; + + if (kidfd != -1) + return (-1); + for (i = 0; i < DA_LEN(&cv); i++) { + c = &DA(&cv)[i]; + if (peer.s_addr == c->peer.s_addr && port == c->port) + return (i); + } + DA_ENSURE(&cv, 1); + DA_EXTEND(&cv, 1); + c = &DA(&cv)[i]; + c->peer = peer; + c->port = port; + return (i); +} + +/* --- @privconn_connect@ --- * + * + * Arguments: @conn *c@ = connection structure to fill in + * @sel_state *s@ = pointer to select state to attach to + * @int i@ = address index to connect to + * @struct in_addr bind@ = address to bind to + * @void (*func)(int, void *)@ = function to call on connect + * @void *p@ = argument for the function + * + * Returns: Zero on success, @-1@ on failure. + * + * Use: Sets up a privileged connection job. + */ + +int privconn_connect(conn *c, sel_state *s, int i, struct in_addr bind, + void (*func)(int, void *), void *p) +{ + int fd; + connrq rq; + ssize_t n; + + rq.i = i; + rq.bind = bind; + if (kidfd == -1) { + if ((fd = doconn(&rq)) < 0) + return (-1); + conn_fd(c, s, fd, func, p); + return (0); + } + + n = write(kidfd, &rq, sizeof(rq)); + if (n < 0) + return (-1); + c->writer.fd = -1; + c->writer.s = s; + c->writer.next = 0; + c->func = func; + c->p = p; + *qtail = c; + qtail = (conn **)&c->writer.next; + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/privconn.h b/privconn.h new file mode 100644 index 0000000..857f278 --- /dev/null +++ b/privconn.h @@ -0,0 +1,102 @@ +/* -*-c-*- + * + * $Id: privconn.h,v 1.1 2003/11/29 20:36:07 mdw Exp $ + * + * Making privileged connections + * + * (c) 2003 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the `fw' port forwarder. + * + * `fw' 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. + * + * `fw' 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 `fw'; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: privconn.h,v $ + * Revision 1.1 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * + */ + +#ifndef PRIVCONN_H +#define PRIVCONN_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include +#include + +/*----- Functions provided ------------------------------------------------*/ + +/* --- @privconn_split@ --- * + * + * Arguments: @sel_state *s@ = select state + * + * Returns: --- + * + * Use: Splits off the privileged binding code into a separate + * process. + */ + +extern void privconn_split(sel_state */*s*/); + +/* --- @privconn_adddest@ --- * + * + * Arguments: @struct in_addr peer@ = address to connect to + * @unsigned port@ = port to connect to + * + * Returns: Index for this destination address, or @-1@ if not + * available. + * + * Use: Adds a valid destination for a privileged connection. + */ + +extern int privconn_adddest(struct in_addr /*peer*/, unsigned /*port*/); + +/* --- @privconn_connect@ --- * + * + * Arguments: @conn *c@ = connection structure to fill in + * @sel_state *s@ = pointer to select state to attach to + * @int i@ = address index to connect to + * @struct in_addr bind@ = address to bind to + * @void (*func)(int, void *)@ = function to call on connect + * @void *p@ = argument for the function + * + * Returns: Zero on success, @-1@ on failure. + * + * Use: Sets up a privileged connection job. + */ + +extern int privconn_connect(conn */*c*/, sel_state */*s*/, + int /*i*/, struct in_addr /*bind*/, + void (*/*func*/)(int, void *), void */*p*/); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/socket.c b/socket.c index 5f1a731..bbc1f9e 100644 --- a/socket.c +++ b/socket.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: socket.c,v 1.10 2003/11/25 14:08:23 mdw Exp $ + * $Id: socket.c,v 1.11 2003/11/29 20:36:07 mdw Exp $ * * Socket source and target definitions * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: socket.c,v $ + * Revision 1.11 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.10 2003/11/25 14:08:23 mdw * Debianization. Socket target options. Internet binding. * @@ -576,6 +579,11 @@ static void ssource_attach(source *s, scanner *sc, target *t) dstr_destroy(&d); } + /* --- Confirm the address --- */ + + if (ss->a->ops->confirm) + ss->a->ops->confirm(ss->a, ADDR_SRC, ss->ao); + /* --- Initialize the socket for listening --- */ if ((fd = ss->a->ops->bind(ss->a, ss->ao)) < 0) @@ -675,15 +683,17 @@ static target *starget_read(scanner *sc) return (&st->t); } -/* --- @create@ --- * - * - * Arguments: @target *t@ = pointer to target - * @const char *desc@ = description of connection - * - * Returns: Pointer to a created endpoint. - * - * Use: Generates a target endpoint for communication. - */ +/* --- @confirm@ --- */ + +static void starget_confirm(target *t) +{ + starget *st = (starget *)t; + + if (st->a->ops->confirm) + st->a->ops->confirm(st->a, ADDR_DEST, st->ao); +} + +/* --- @create@ --- */ static endpt *starget_create(target *t, const char *desc) { @@ -722,7 +732,8 @@ static void starget_destroy(target *t) target_ops starget_ops = { "socket", - starget_option, starget_read, starget_create, starget_destroy + starget_option, starget_read, starget_confirm, + starget_create, starget_destroy }; /*----- That's all, folks -------------------------------------------------*/ diff --git a/target.h b/target.h index 862527a..1472ff3 100644 --- a/target.h +++ b/target.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: target.h,v 1.2 2003/11/25 14:08:23 mdw Exp $ + * $Id: target.h,v 1.3 2003/11/29 20:36:07 mdw Exp $ * * Description of forwarding targets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: target.h,v $ + * Revision 1.3 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.2 2003/11/25 14:08:23 mdw * Debianization. Socket target options. Internet binding. * @@ -95,6 +98,17 @@ typedef struct target_ops { target *(*read)(scanner */*sc*/); + /* --- @confirm@ --- * + * + * Arguments: @target *t@ = pointer to target + * + * Returns: --- + * + * Use: Confirms configuration of a target. + */ + + void (*confirm)(target */*t*/); + /* --- @create@ --- * * * Arguments: @target *t@ = pointer to target diff --git a/un.c b/un.c index e415256..f701f6a 100644 --- a/un.c +++ b/un.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: un.c,v 1.6 2003/11/25 14:08:23 mdw Exp $ + * $Id: un.c,v 1.7 2003/11/29 20:36:07 mdw Exp $ * * Protocol specific definitions for Unix-domain sockets * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: un.c,v $ + * Revision 1.7 2003/11/29 20:36:07 mdw + * Privileged outgoing connections. + * * Revision 1.6 2003/11/25 14:08:23 mdw * Debianization. Socket target options. Internet binding. * @@ -251,7 +254,7 @@ fail_0: addr_ops un_ops = { "unix", un_read, un_destroy, un_print, - un_initopts, un_option, un_freeopts, un_bind, un_unbind, un_accept, + un_initopts, un_option, 0, un_freeopts, un_bind, un_unbind, un_accept, 0, 0, un_connect }; -- 2.11.0 From 092f30889fdc6895dceaeee40e3466ed503f2e54 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 29 Nov 2003 20:43:01 +0000 Subject: [PATCH 14/16] Don't do priv separation if no priv connections to make. --- privconn.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/privconn.c b/privconn.c index fcd292b..b2dfaef 100644 --- a/privconn.c +++ b/privconn.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: privconn.c,v 1.1 2003/11/29 20:36:07 mdw Exp $ + * $Id: privconn.c,v 1.2 2003/11/29 20:43:01 mdw Exp $ * * Making privileged connections * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: privconn.c,v $ + * Revision 1.2 2003/11/29 20:43:01 mdw + * Don't do priv separation if no priv connections to make. + * * Revision 1.1 2003/11/29 20:36:07 mdw * Privileged outgoing connections. * @@ -285,7 +288,7 @@ void privconn_split(sel_state *s) pid_t kid; int fd[2]; - if (kidfd != -1) + if (kidfd != -1 || DA_LEN(&cv) == 0) return; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0) die(1, "couldn't create privconn socketpair: %s", strerror(errno)); -- 2.11.0 From 9df1a2f2b4e3af5e03f85aebea94e25d46231bf4 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 29 Nov 2003 20:45:41 +0000 Subject: [PATCH 15/16] Require mLib 2.0.3 for connection stuff. --- configure.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 51ca5b7..5cd455c 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl -*-m4-*- dnl -dnl $Id: configure.in,v 1.16 2003/11/25 14:11:18 mdw Exp $ +dnl $Id: configure.in,v 1.17 2003/11/29 20:45:41 mdw Exp $ dnl dnl Configuration script for fw dnl @@ -28,6 +28,9 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. dnl ----- Revision history -------------------------------------------------- dnl dnl $Log: configure.in,v $ +dnl Revision 1.17 2003/11/29 20:45:41 mdw +dnl Require mLib 2.0.3 for connection stuff. +dnl dnl Revision 1.16 2003/11/25 14:11:18 mdw dnl Preliminary bump to 1.2.7. dnl @@ -79,7 +82,7 @@ mdw_DECL_ENVIRON mdw_CHECK_MANYLIBS(socket, socket) mdw_CHECK_MANYLIBS(gethostbyname, nsl resolv) -mdw_MLIB(2.0.2) +mdw_MLIB(2.0.3) AC_CHECK_FUNCS(inet_aton) AC_CHECK_FUNCS(setrlimit) -- 2.11.0 From bdbbfcd4eb2f6e15270f558342630d964cb9f418 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 29 Nov 2003 22:13:43 +0000 Subject: [PATCH 16/16] Fix bug in identification timout handling. --- identify.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/identify.c b/identify.c index f94cc0e..e35799c 100644 --- a/identify.c +++ b/identify.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: identify.c,v 1.8 2003/11/29 20:36:07 mdw Exp $ + * $Id: identify.c,v 1.9 2003/11/29 22:13:43 mdw Exp $ * * Identifies and logs the client of a connection * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: identify.c,v $ + * Revision 1.9 2003/11/29 22:13:43 mdw + * Fix bug in identification timout handling. + * * Revision 1.8 2003/11/29 20:36:07 mdw * Privileged outgoing connections. * @@ -206,6 +209,7 @@ static void id_ident(ident_reply *ir, void *vp) static void id_timer(struct timeval *tv, void *vp) { id *i = vp; + i->state |= S_TIMER: id_done(i); } -- 2.11.0