X-Git-Url: https://git.distorted.org.uk/~mdw/fwd/blobdiff_plain/e82f7154f65062d9ac8b9677862774498b331058..a9bd543ab4ebe415bca9d6f27b90f16ddac79bc0:/fw.h diff --git a/fw.h b/fw.h index 8c87832..0206b2e 100644 --- a/fw.h +++ b/fw.h @@ -1,13 +1,11 @@ /* -*-c-*- * - * $Id: fw.h,v 1.1 1999/07/01 08:56:23 mdw Exp $ - * * Main header file for port forwarder * - * (c) 1999 Mark Wooding + * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of the `fw' port forwarder. * @@ -15,25 +13,17 @@ * 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: fw.h,v $ - * Revision 1.1 1999/07/01 08:56:23 mdw - * Initial revision - * - */ - #ifndef FW_H #define FW_H @@ -43,12 +33,1372 @@ /*----- Header files ------------------------------------------------------*/ +/* --- Configuration --- */ + +#include "config.h" +#define _GNU_SOURCE + +/* --- ANSI C --- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --- Unix --- */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* --- mLib --- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include + +/*----- Other subtleties --------------------------------------------------*/ + +#if defined(HAVE_DECL_ENVIRON) && !HAVE_DECL_ENVIRON + extern char **environ; +#endif -/*----- Global variables --------------------------------------------------*/ +/*----- Main program ------------------------------------------------------*/ + +/* --- The global select state --- */ extern sel_state *sel; +/* --- Help text --- */ + +extern const char grammar_text[]; +extern const char option_text[]; + +/* --- @fw_log@ --- * + * + * Arguments: @time_t t@ = when the connection occurred or (@-1@) + * @const char *fmt@ = format string to fill in + * @...@ = other arguments + * + * Returns: --- + * + * Use: Logs a connection. + */ + +extern void fw_log(time_t /*t*/, const char */*fmt*/, ...); + +/* --- @fw_inc@, @fw_dec@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Increments or decrements the active thing count. `fw' won't + * quit while there are active things. + */ + +extern void fw_inc(void); +extern void fw_dec(void); + +/*----- Channel management ------------------------------------------------*/ + +/* --- Magic numbers --- */ + +#define CHAN_BUFSZ 4096 + +/* --- Channel structure --- */ + +typedef struct chan { + unsigned base, len; /* Base and length of data */ + unsigned f; /* Various interesting flags */ + void (*func)(void */*p*/); /* Function to call on closure */ + void *p; /* Argument to pass function */ + sel_file r, w; /* Reader and writer selectors */ + char buf[CHAN_BUFSZ]; /* The actual data buffer */ +} chan; + +#define CHANF_CLOSE 1u /* Close channel when buffer empty */ +#define CHANF_READY 2u /* The channel destination exists */ + +/* --- @chan_close@ --- * + * + * Arguments: @chan *c@ = pointer to channel + * + * Returns: --- + * + * Use: Closes down a channel prematurely. + */ + +extern void chan_close(chan */*c*/); + +/* --- @chan_dest@ --- * + * + * Arguments: @chan *c@ = pointer to channel + * @int fd@ = destination file descriptor for channel + * + * Returns: --- + * + * Use: Sets the channel's destination so it knows where to put + * data. + */ + +extern void chan_dest(chan */*c*/, int /*fd*/); + +/* --- @chan_open@ --- * + * + * Arguments: @chan *c@ = pointer to channel to open + * @int from, to@ = source and destination file descriptors + * @void (*func)(void *p)@ = function to call on closure + * @void *p@ = argument to pass to function + * + * Returns: --- + * + * Use: Opens a channel. Data is copied from the source to the + * destination. The @to@ argument may be @-1@ if the file + * descriptor isn't known yet. + */ + +extern void chan_open(chan */*c*/, int /*from*/, int /*to*/, + void (*/*func*/)(void */*p*/), void */*p*/); + +/*----- Character scanners ------------------------------------------------*/ + +/* --- A low-level scanner source --- */ + +typedef struct scansrc { + struct scansrc *next; /* Next one in the list */ + struct scansrc_ops *ops; /* Pointer to operations table */ + char *src; /* Name of this source */ + int line; /* Current line number */ + dstr pushback; /* Pushback characters */ + char *tok; /* Token pushback */ + unsigned t; /* Token type pushback */ +} scansrc; + +/* --- Scanner source operations --- */ + +typedef struct scansrc_ops { + int (*scan)(scansrc */*ss*/); /* Read another character */ + void (*destroy)(scansrc */*ss*/); /* Destroy an unwanted source */ +} scansrc_ops; + +/* --- A character scanner --- */ + +typedef struct scanner { + scansrc *head, **tail; /* Scanner list head and tail */ + int t; /* Token type */ + dstr d; /* Current token value */ + const char *wbegin, *wcont; /* Parsing exception strings */ +} scanner; + +/* --- @scan_file@ --- * + * + * Arguments: @FILE *fp@ = pointer to file descriptor + * @const char *name@ = pointer to source file name + * @unsigned f@ = flags + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from a file. + */ + +#define SCF_NOCLOSE 1u /* Don't close @fp@ when finished */ + +extern scansrc *scan_file(FILE */*fp*/, const char */*name*/, + unsigned /*f*/); + +/* --- @scan_argv@ --- * + * + * Arguments: @char **av@ = pointer to argument array (null terminated) + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from an @argv@ + * array. + */ + +extern scansrc *scan_argv(char **/*av*/); + +/* --- @scan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * + * Returns: Character read, or end-of-file. + * + * Use: Scans a character from a source of characters. + */ + +extern int scan(scanner */*sc*/); + +/* --- @unscan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @int ch@ = character to unscan + * + * Returns: --- + * + * Use: Scans a character from a source of characters. + */ + +extern void unscan(scanner */*sc*/, int /*ch*/); + +/* --- @scan_push@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Pushes a scanner source onto the front of the queue. + */ + +extern void scan_push(scanner */*sc*/, scansrc */*ss*/); + +/* --- @scan_add@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Adds a scanner source onto the end of the queue. + */ + +extern void scan_add(scanner */*sc*/, scansrc */*ss*/); + +/* --- @scan_create@ --- * + * + * Arguments: @scanner *sc@ = scanner context to initialize + * + * Returns: --- + * + * Use: Initializes a scanner block ready for use. + */ + +extern void scan_create(scanner */*sc*/); + +/* --- @scan_destroy@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner context + * + * Returns: --- + * + * Use: Destroys a scanner and all the sources attached to it. + */ + +extern void scan_destroy(scanner */*sc*/); + +/*----- Configuration parsing ---------------------------------------------*/ + +/* --- Magical constants --- */ + +#define CTOK_EOF (-1) +#define CTOK_WORD 256 + +/* --- @conf_undelim@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner definition + * @const char *d, *dd@ = pointer to characters to escape + * + * Returns: --- + * + * Use: Modifies the tokenizer. Characters in the first list will + * always be considered to begin a word. Characters in the + * second list will always be allowed to continue a word. + */ + +extern void conf_undelim(scanner */*sc*/, + const char */*d*/, const char */*dd*/); + +/* --- @token@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner definition + * + * Returns: Type of token scanned. + * + * Use: Reads the next token from the character scanner. + */ + +extern int token(scanner */*sc*/); + +/* --- @error@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner definition + * @const char *msg@ = message skeleton string + * @...@ = extra arguments for the skeleton + * + * Returns: Doesn't + * + * Use: Reports an error at the current scanner location. + */ + +extern void error(scanner */*sc*/, const char */*msg*/, ...); + +/* --- @pushback@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner definition + * + * Returns: --- + * + * Use: Pushes the current token back. This is normally a precursor + * to pushing a new scanner source. + */ + +extern void pushback(scanner */*sc*/); + +/* --- @conf_enum@ --- * + * + * Arguments: @scanner *sc@ = pointer to a scanner object + * @const char *list@ = comma-separated things to allow + * @unsigned @f = flags for the search + * @const char *err@ = error message if not found + * + * Returns: Index into list, zero-based, or @-1@. + * + * Use: Checks whether the current token is a string which matches + * one of the comma-separated items given. The return value is + * the index (zero-based) of the matched string in the list. + * + * The flags control the behaviour if no exact match is found. + * If @ENUM_ABBREV@ is set, and the current token is a left + * substring of exactly one of the possibilities, then that one + * is chosen. If @ENUM_NONE@ is set, the value @-1@ is + * returned; otherwise an error is reported and the program is + * terminated. + */ + +#define ENUM_ABBREV 1u +#define ENUM_NONE 2u + +extern int conf_enum(scanner */*sc*/, const char */*list*/, + unsigned /*flags*/, const char */*err*/); + +/* --- @conf_prefix@ --- * + * + * Arguments: @scanner *sc@ = pointer to a scanner object + * @const char *p@ = pointer to prefix string to check + * + * Returns: Nonzero if the prefix matches. + * + * Use: If the current token is a word matching the given prefix + * string, then it and an optional `.' character are removed and + * a nonzero result is returned. Otherwise the current token is + * left as it is, and zero is returned. + * + * Typical options parsing code would remove an expected prefix, + * scan an option anyway (since qualifying prefixes are + * optional) and if a match is found, claim the option. If no + * match is found, and a prefix was stripped, then an error + * should be reported. + */ + +extern int conf_prefix(scanner */*sc*/, const char */*p*/); + +/* --- @CONF_BEGIN@, @CONF_END@ --- * + * + * Arguments: @sc@ = scanner to read from + * @prefix@ = prefix to scan for + * @desc@ = description of what we're parsing + * + * Use: Bracket an options parsing routine. The current token is + * checked to see whether it matches the prefix. If so, it is + * removed and the following token examined. If that's a `.' + * then it's removed. If it's a `{' then the enclosed + * option-parsing code is executed in a loop until a matching + * '}' is found. If the options parser doesn't accept an + * option, the behaviour is dependent on whether a prefix was + * seen: if so, an error is reported; otherwse a zero return is + * made. + */ + +#define CS_PLAIN 0 +#define CS_PREFIX 1 +#define CS_BRACE 2 +#define CS_UNKNOWN 3 + +#define CONF_BEGIN(sc, prefix, desc) do { \ + scanner *_conf_sc = (sc); \ + const char *_conf_desc = (desc); \ + int _conf_state = CS_PLAIN; \ + \ + /* --- Read the initial prefix --- */ \ + \ + if (_conf_sc->t == CTOK_WORD && \ + strcmp(_conf_sc->d.buf, (prefix)) == 0) { \ + token(_conf_sc); \ + _conf_state = CS_PREFIX; \ + if (_conf_sc->t == '.') \ + token(_conf_sc); \ + else if (_conf_sc->t == '{') { \ + token(_conf_sc); \ + _conf_state = CS_BRACE; \ + } \ + } \ + \ + /* --- Ensure the next token is a word --- */ \ + \ + if (_conf_sc->t != CTOK_WORD) \ + error(_conf_sc, "parse error, expected option keyword"); \ + do { + +#define CONF_END \ + \ + /* --- Reject an option --- * \ + * \ + * We could get here as a result of an explicit @CONF_REJECT@ or \ + * because the option wasn't accepted. \ + */ \ + \ + goto _conf_reject; \ + _conf_reject: \ + if (_conf_state == CS_PLAIN) \ + _conf_state = CS_UNKNOWN; \ + else { \ + error(_conf_sc, "unknown %s option `%s'", \ + _conf_desc, _conf_sc->d.buf); \ + } \ + \ + /* --- Accept an option --- * \ + * \ + * It's safe to drop through from above. Either an error will have \ + * been reported, or the state is not @CS_BRACE@. \ + */ \ + \ + _conf_accept: \ + if (_conf_state == CS_BRACE && _conf_sc->t == ';') \ + token(_conf_sc); \ + } while (_conf_state == CS_BRACE && _conf_sc->t == CTOK_WORD); \ + \ + /* --- Check for a closing brace --- */ \ + \ + if (_conf_state == CS_BRACE) { \ + if (_conf_sc->t == '}') \ + token(_conf_sc); \ + else \ + error(_conf_sc, "parse error, expected `}'"); \ + } \ + \ + /* --- Return an appropriate value --- */ \ + \ + return (_conf_state != CS_UNKNOWN); \ +} while (0) + +/* --- @CONF_ACCEPT@, @CONF_REJECT@ --- * + * + * Arguments: --- + * + * Use: Within an options parser (between @CONF_BEGIN@ and + * @CONF_END@), accept or reject an option. + */ + +#define CONF_ACCEPT goto _conf_accept +#define CONF_REJECT goto _conf_reject + +/* --- @CONF_QUAL@ --- * + * + * Arguments: --- + * + * Use: Evaluates to a nonzero value if the current option is + * qualified. This can be used to decide whether abbreviations + * for options should be accepted. + */ + +#define CONF_QUAL (_conf_state != CS_PLAIN) + +/* --- @conf_name@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner + * @char delim@ = delimiter character to look for + * @dstr *d@ = pointer to dynamic string for output + * + * Returns: --- + * + * Use: Reads in a compound name consisting of words separated by + * delimiters. Leading and trailing delimiters are permitted, + * although they'll probably cause confusion if used. The name + * may be enclosed in square brackets if that helps at all. + * + * Examples of compound names are filenames (delimited by `/') + * and IP addresses (delimited by `.'). + */ + +extern void conf_name(scanner */*sc*/, char /*delim*/, dstr */*d*/); + +/*----- Reference-counted file descriptors --------------------------------*/ + +typedef struct reffd { + int fd; + unsigned ref; + void (*proc)(void */*p*/); + void *p; +} reffd; + +/* --- @reffd_init@ --- * + * + * Arguments: @int fd@ = file descriptor + * + * Returns: Reference-counted file descriptor object. + * + * Use: Creates a refcounted file descriptor. + */ + +extern reffd *reffd_init(int /*fd*/); + +/* --- @reffd_handler@ --- * + * + * Arguments: @reffd *r@ = pointer to reference counted filehandle + * @void (*proc)(void *p)@ = procedure to call + * @void *p@ + * + * Returns: --- + * + * Use: Sets the reference counted file descriptor to call @proc@ + * when it is no longer required. + */ + +extern void reffd_handler(reffd */*r*/, void (*/*proc*/)(void */*p*/), + void */*p*/); + +/* --- @reffd_inc@ --- * + * + * Arguments: @reffd *r@ = pointer to reference counted filehandle + * + * Returns: --- + * + * Use: Increments the reference count for a file descriptor. + */ + +#define REFFD_INC(r) do { (r)->ref++; } while (0) + +extern void reffd_inc(reffd */*r*/); + +/* --- @reffd_dec@ --- * + * + * Arguments: @reffd *r@ = pointer to reference counted filehandle + * + * Returns: --- + * + * Use: Decrements the reference count for a file descriptor. + */ + +#define REFFD_DEC(r) do { \ + reffd *_r = (r); \ + _r->ref--; \ + if (_r->ref == 0) { \ + close(_r->fd); \ + if (_r->proc) \ + _r->proc(_r->p); \ + DESTROY(_r); \ + } \ +} while (0) + +extern void reffd_dec(reffd */*r*/); + +/*----- Sources, targets and endpoints ------------------------------------*/ + +/* --- Basic endpoint structure --- */ + +typedef struct endpt { + struct endpt_ops *ops; /* Pointer to operations table */ + struct endpt *other; /* Pointer to sibling endpoint */ + unsigned f; /* Various flags */ + struct tango *t; /* Private data structure */ + reffd *in, *out; /* File descriptors */ +} endpt; + +/* --- Endpoint flags --- */ + +#define EPF_PENDING 1u /* Endpoint creation in progress */ +#define EPF_FILE 2u /* Endpoint smells like a file */ + +/* --- Endpoint operations table --- */ + +typedef struct endpt_ops { + + /* --- @attach@ --- * + * + * Arguments: @endpt *e@ = pointer to endpoint to be attached + * @reffd *in, *out@ = input and output file descriptors + * + * Returns: --- + * + * Use: Instructs a non-file endpoint to attach itself to a pair of + * files. + */ + + void (*attach)(endpt */*e*/, reffd */*in*/, reffd */*out*/); + + /* --- @file@ --- * + * + * Arguments: @endpt *e@ = pointer to endpoint in question + * @endpt *f@ = pointer to a file endpoint + * + * Returns: --- + * + * Use: Informs a non-file endpoint of a file endpoint which will + * want to be closed when it's finished with. At that time, the + * endpoint should arrange to have both itself and its partner + * closed. If no file is registered, the endpoint manager will + * close both endpoints itself. + */ + + void (*file)(endpt */*e*/, endpt */*f*/); + + /* --- @wclose@ --- * + * + * Arguments: @endpt *e@ = endpoint to be partially closed + * + * Returns: --- + * + * Use: Announces that the endpoint will not be written to any more. + */ + + void (*wclose)(endpt */*e*/); + + /* --- @close@ --- * + * + * Arguments: @endpt *e@ = endpoint to be closed + * + * Returns: --- + * + * Use: Completely closes an endpoint. The endpoint's data may be + * freed, although some endpoints may wish to delay freeing for + * some reason. + */ + + void (*close)(endpt */*e*/); + +} endpt_ops; + +/* --- A basic target object --- */ + +typedef struct target { + struct target_ops *ops; + char *desc; +} target; + +/* --- Forwarding target operations --- */ + +typedef struct target_ops { + const char *name; /* Name of this target */ + + /* --- @option@ --- * + * + * Arguments: @target *t@ = pointer to target object, or zero if global + * @scanner *sc@ = scanner to read from + * + * Returns: Nonzero to claim the option. + * + * Use: Handles an option string from the configuration file. + */ + + int (*option)(target */*t*/, scanner */*sc*/); + + /* --- @read@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner to read from + * + * Returns: Pointer to a target object to claim, null to reject. + * + * Use: Parses a target description from the configuration file. + * Only the socket target is allowed to omit the prefix on a + * target specification. + */ + + 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 + * @const char *desc@ = description of connection + * + * Returns: Pointer to a created endpoint. + * + * Use: Generates a target endpoint for communication. + */ + + endpt *(*create)(target */*t*/, const char */*desc*/); + + /* --- @destroy@ --- * + * + * Arguments: @target *t@ = pointer to target + * + * Returns: --- + * + * Use: Destroys a target. + */ + + void (*destroy)(target */*t*/); + +} target_ops; + +/* --- A basic source object --- */ + +typedef struct source { + struct source *next, *prev; + struct source_ops *ops; + char *desc; +} source; + +/* --- Forwarding source operations --- */ + +typedef struct source_ops { + const char *name; /* Name of this source */ + + /* --- @option@ --- * + * + * Arguments: @scanner *sc@ = scanner to read from + * @source *s@ = pointer to source object, or zero if global + * + * Returns: Nonzero to claim the option. + * + * Use: Handles an option string from the configuration file. + */ + + int (*option)(source */*s*/, scanner */*sc*/); + + /* --- @read@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner to read from + * + * Returns: Pointer to a source object to claim, null to reject. + * + * Use: Parses a source description from the configuration file. + * Only the socket source is allowed to omit the prefix on a + * source specification. + */ + + source *(*read)(scanner */*sc*/); + + /* --- @attach@ --- * + * + * Arguments: @source *s@ = pointer to source + * @scanner *sc@ = scanner (for error reporting) + * @target *t@ = pointer to target to attach + * + * Returns: --- + * + * Use: Attaches a target to a source. + */ + + void (*attach)(source */*s*/, scanner */*sc*/, target */*t*/); + + /* --- @destroy@ --- * + * + * Arguments: @source *s@ = pointer to source + * + * Returns: --- + * + * Use: Destroys a source. Used when closing the system down, for + * example as a result of a signal. + */ + + void (*destroy)(source */*s*/); + +} source_ops; + +/* --- @endpt_kill@ --- * + * + * Arguments: @endpt *a@ = an endpoint + * + * Returns: --- + * + * Use: Kills an endpoint. If the endpoint is joined to another, the + * other endpoint is also killed, as is the connection between + * them (and that's the tricky bit). + */ + +extern void endpt_kill(endpt */*a*/); + +/* --- @endpt_killall@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Destroys all current endpoint connections. Used when + * shutting down. + */ + +extern void endpt_killall(void); + +/* --- @endpt_join@ --- * + * + * Arguments: @endpt *a@ = pointer to first endpoint + * @endpt *b@ = pointer to second endpoint + * + * Returns: --- + * + * Use: Joins two endpoints together. + */ + +extern void endpt_join(endpt */*a*/, endpt */*b*/); + +/* --- @source_add@ --- * + * + * Arguments: @source *s@ = pointer to a source + * + * Returns: --- + * + * Use: Adds a source to the master list. Only do this for passive + * sources (e.g., listening sockets), not active sources (e.g., + * executable programs). + */ + +extern void source_add(source */*s*/); + +/* --- @source_remove@ --- * + * + * Arguments: @source *s@ = pointer to a source + * + * Returns: --- + * + * Use: Removes a source from the master list. + */ + +extern void source_remove(source */*s*/); + +/* --- @source_killall@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Frees all sources. + */ + +extern void source_killall(void); + +/*----- The exec source and target ----------------------------------------*/ + +extern source_ops xsource_ops; +extern target_ops xtarget_ops; + +/* --- @exec_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Initializes the executable problem source and target. + */ + +extern void exec_init(void); + +/*----- The file source and target ----------------------------------------*/ + +extern source_ops fsource_ops; +extern target_ops ftarget_ops; + +/*----- The socket source and target --------------------------------------*/ + +extern source_ops ssource_ops; +extern target_ops starget_ops; + +/* --- @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*/); + +/*----- Handling of file attributes ---------------------------------------*/ + +/* --- File attribute options structure --- */ + +typedef struct fattr { + unsigned mode; + uid_t uid; + gid_t gid; +} fattr; + +/* --- Shared global options --- */ + +extern fattr fattr_global; + +/* --- @fattr_init@ --- * + * + * Arguments: @fattr *f@ = pointer to file attributes + * + * Returns: --- + * + * Use: Initializes a set of file attributes to default values. + */ + +extern void fattr_init(fattr */*f*/); + +/* --- @fattr_option@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner to read + * @fattr *f@ = pointer to file attributes to set + * + * Returns: Whether the option was clamed. + * + * Use: Reads file attributes from a scanner. + */ + +extern int fattr_option(scanner */*sc*/, fattr */*f*/); + +/* --- @fattr_apply@ --- * + * + * Arguments: @const char *file@ = pointer to filename + * @fattr *f@ = pointer to attribute set + * + * Returns: @-1@ if it failed. + * + * Use: Applies file attributes to a file. For best results, try to + * create the file with the right permissions and so on. This + * call will fix everything up, but there are potential races + * which might catch you out if you're not careful. + */ + +extern int fattr_apply(const char */*file*/, fattr */*f*/); + +/*----- Making privileged connections -------------------------------------*/ + +/* --- @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*/); + +/*----- Identifying remote clients ----------------------------------------*/ + +typedef struct id_req { + struct sockaddr_in lsin; /* Local address of connection */ + struct sockaddr_in rsin; /* Remote address of connection */ + const char *desc; /* Description of connection */ + const char *act; /* Action taken by server */ + reffd *r; /* Pointer to file descriptor */ +} id_req; + +/* --- @identify@ --- * + * + * Arguments: @const id_req *q@ = pointer to request block + * + * Returns: --- + * + * Use: Starts a background ident lookup and reverse-resolve job + * which will, eventually, report a message to the system log. + */ + +extern void identify(const id_req */*q*/); + +/*----- Host-based access control -----------------------------------------*/ + +/* --- An access control entry --- */ + +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 */ +} acl_entry; + +#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; + +/* --- @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: 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*/, unsigned /*port*/, + int */*act*/); + +/* --- @acl_dump@ --- * + * + * Arguments: @acl_entry *a@ = pointer to ACL to dump + * @FILE *fp@ = pointer to stream to dump on + * + * Returns: --- + * + * Use: Dumps an access control list to an output stream. + */ + +extern void acl_dump(acl_entry */*a*/, FILE */*fp*/); + +/* --- @acl_free@ --- * + * + * Arguments: @acl_entry *a@ = pointer to a list of ACLs + * + * Returns: --- + * + * Use: Frees all of the memory used by an ACL. + */ + +extern void acl_free(acl_entry */*a*/); + +/* --- @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. + */ + +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_addpriv(acl_entry ***/*a*/, unsigned /*act*/); + +/*----- Network addresses -------------------------------------------------*/ + +/* --- A generic socket address --- * + * + * Not all systems understand @sa_len@ fields. (In particular, Linux + * doesn't.) Some fairly ugly hacking is then performed on particular + * address types. + */ + +typedef struct addr { + struct addr_ops *ops; + size_t sz; +} addr; + +#define ADDRSZ(sz) (sizeof(addr) + (sz)) + +/* --- Address configuration --- * + * + * An address family will want to extend this. + */ + +typedef struct addr_opts { + unsigned f; +} addr_opts; + +#define ADDRF_NOLOG 1u + +/* --- Address types --- * + * + * For things like Internet addresses, source and destinations look + * different. + */ + +enum { + ADDR_SRC, + ADDR_DEST, + ADDR_GLOBAL +}; + +/* --- Description of an address type handler --- */ + +typedef struct addr_ops { + const char *name; /* Protocol's internal name */ + + /* --- @read@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner to read from + * @unsigned type@ = type of address to be read + * + * Returns: A filled-in socket address. + * + * Use: Parses a textual representation of a socket address. + */ + + addr *(*read)(scanner */*sc*/, unsigned /*type*/); + + /* --- @destroy@ --- * + * + * Arguments: @addr *a@ = pointer to an address block + * + * Returns: --- + * + * Use: Disposes of an address block in some suitable fashion. + */ + + void (*destroy)(addr */*a*/); + + /* --- @print@ --- * + * + * Arguments: @addr *a@ = pointer to socket address to read + * @unsigned type@ = type of address to be written + * @dstr *d@ = string on which to write the description + * + * Returns: --- + * + * Use: Writes a textual representation of a socket address to + * a string. + */ + + void (*print)(addr */*a*/, unsigned /*type*/, dstr */*d*/); + + /* --- @initsrcopts@ --- * + * + * Arguments: --- + * + * Returns: A pointer to a protocol-specific data block for a listener + * + * Use: Creates a data block for a listener. This is attached to the + * listener data structure. Options can then be requested, and + * are added to the block when necessary. + */ + + 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 a source option, either global or listener-specific. + */ + + 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 + * + * 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. + */ + + void (*unbind)(addr */*a*/); + + /* --- @accept@ --- * + * + * Arguments: @int fd@ = listening file descriptor + * @addr_opts *ao@ = data block to get configuration from + * @const char *desc@ = description of the listener + * + * Returns: Pointer to a reference counted file descriptor. + * + * Use: Accepts, verifies and logs an incoming connection. + */ + + reffd *(*accept)(int /*fd*/, addr_opts */*ao*/, const char */*desc*/); + + /* --- @inittargopts@ --- * + * + * Arguments: --- + * + * Returns: A pointer to a protocol-specific data block for a connecter + * + * 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. + */ + + addr_opts *(*inittargopts)(void); + + /* --- @freetargopts@ --- * + * + * Arguments: @addr_opts *ao@ = data block to remove + * + * Returns: --- + * + * Use: Throws away all the configuration data for an address type. + */ + + void (*freetargopts)(addr_opts */*ao*/); + + /* --- @connect@ --- * + * + * Arguments: @addr *a@ = destination address + * @addr_opts *ao@ = target address options + * @conn *c@ = connection structure + * @endpt *e@ = endpoint structure + * + * Returns: Zero if OK, @-1@ on some error. + * + * 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. + */ + + int (*connect)(addr */*a*/, addr_opts */*ao*/, conn */*c*/, endpt */*e*/); + +} addr_ops; + +/* --- Address types --- */ + +extern addr_ops un_ops; +extern addr_ops inet_ops; + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus