X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=secnet.git;a=blobdiff_plain;f=secnet.h;h=21b94c090b7a28ab5ed0c6c7d7c5cab8eebf7031;hp=7d1edb0737d6709714973f9b438a66bddd5a08c5;hb=31dd07884afd1f1d87d398bf344e1ba3a71e293b;hpb=55e96f163095fc9286e0566fdaa1b1df45631fe3 diff --git a/secnet.h b/secnet.h index 7d1edb0..21b94c0 100644 --- a/secnet.h +++ b/secnet.h @@ -1,4 +1,22 @@ /* Core interface of secnet, to be used by all modules */ +/* + * This file is part of secnet. + * See README for full list of copyright holders. + * + * secnet 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 3 of the License, or + * (at your option) any later version. + * + * secnet 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 + * version 3 along with secnet; if not, see + * https://www.gnu.org/licenses/gpl.html. + */ #ifndef secnet_h #define secnet_h @@ -13,12 +31,18 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include #include +#include + #define MAX_PEER_ADDRS 5 /* send at most this many copies; honour at most that many addresses */ @@ -55,6 +79,16 @@ extern struct log_if *system_log; /* from process.c */ extern void start_signal_handling(void); +void afterfork(void); +/* Must be called before exec in every child made after + start_signal_handling. Safe to call in earlier children too. */ + +void childpersist_closefd_hook(void *fd_p, uint32_t newphase); +/* Convenience hook function for use with add_hook PHASE_CHILDPERSIST. + With `int fd' in your state struct, pass fd_p=&fd. The hook checks + whether fd>=0, so you can use it for an fd which is only sometimes + open. This function will set fd to -1, so it is idempotent. */ + /***** CONFIGURATION support *****/ extern bool_t just_check_config; /* If True then we're going to exit after @@ -138,6 +172,8 @@ extern uint32_t dict_read_number(dict_t *dict, cstring_t key, bool_t required, /* return value can safely be assigned to int32_t */ extern bool_t dict_read_bool(dict_t *dict, cstring_t key, bool_t required, cstring_t desc, struct cloc loc, bool_t def); +extern dict_t *dict_read_dict(dict_t *dict, cstring_t key, bool_t required, + cstring_t desc, struct cloc loc); const char **dict_read_string_array(dict_t *dict, cstring_t key, bool_t required, cstring_t desc, struct cloc loc, const char *const *def); @@ -162,8 +198,21 @@ extern uint32_t string_list_to_word(list_t *l, struct flagstr *f, extern char *safe_strdup(const char *string, const char *message); extern void *safe_malloc(size_t size, const char *message); extern void *safe_malloc_ary(size_t size, size_t count, const char *message); +extern void *safe_realloc_ary(void *p, size_t size, size_t count, + const char *message); + +#define NEW(p) \ + ((p)=safe_malloc(sizeof(*(p)), \ + __FILE__ ":" #p)) +#define NEW_ARY(p,count) \ + ((p)=safe_malloc_ary(sizeof(*(p)),(count), \ + __FILE__ ":" #p "[" #count "]")) +#define REALLOC_ARY(p,count) \ + ((p)=safe_realloc_ary((p),sizeof(*(p)),(count), \ + __FILE__ ":" #p "[" #count "]")) void setcloexec(int fd); /* cannot fail */ +void setnonblock(int fd); /* cannot fail */ void pipe_cloexec(int fd[2]); /* pipe(), setcloexec() twice; cannot fail */ extern int sys_cmd(const char *file, const char *argc, ...); @@ -193,20 +242,37 @@ int32_t calculate_max_start_pad(void); /* If nfds_io is insufficient for your needs, set it to the required number and return ERANGE. timeout is in milliseconds; if it is too - high then lower it. It starts at -1 (==infinite) */ + high then lower it. It starts at -1 (==infinite). */ +/* Note that beforepoll_fn may NOT do anything which might change the + fds or timeouts wanted by other registered poll loop loopers. + Callers should make sure of this by not making any calls into other + modules from the beforepoll_fn; the easiest way to ensure this is + for beforepoll_fn to only retreive information and not take any + action. + */ typedef int beforepoll_fn(void *st, struct pollfd *fds, int *nfds_io, int *timeout_io); typedef void afterpoll_fn(void *st, struct pollfd *fds, int nfds); + /* If beforepoll_fn returned ERANGE, afterpoll_fn gets nfds==0. + afterpoll_fn never gets !!(fds[].revents & POLLNVAL) - such + a report is detected as a fatal error by the event loop. */ + +/* void BEFOREPOLL_WANT_FDS(int want); + * Expects: int *nfds_io; + * Can perform non-local exit. + * Checks whether there is space for want fds. If so, sets *nfds_io. + * If not, sets *nfds_io and returns. */ +#define BEFOREPOLL_WANT_FDS(want) do{ \ + if (*nfds_io<(want)) { *nfds_io=(want); return ERANGE; } \ + *nfds_io=(want); \ + }while(0) /* Register interest in the main loop of the program. Before a call to poll() your supplied beforepoll function will be called. After - the call to poll() the supplied afterpoll function will be called. - max_nfds is a _hint_ about the maximum number of struct pollfd - structures you may require - you can always ask for more in - *nfds_io. */ -extern void register_for_poll(void *st, beforepoll_fn *before, - afterpoll_fn *after, int32_t max_nfds, - cstring_t desc); + the call to poll() the supplied afterpoll function will be called. */ +struct poll_interest *register_for_poll(void *st, beforepoll_fn *before, + afterpoll_fn *after, cstring_t desc); +void deregister_for_poll(struct poll_interest *i); /***** END of scheduling support */ @@ -229,10 +295,18 @@ enum phase { PHASE_DROPPRIV, /* Last chance for privileged operations */ PHASE_RUN, PHASE_SHUTDOWN, /* About to die; delete key material, etc. */ + PHASE_CHILDPERSIST, /* Forked long-term child: close fds, etc. */ /* Keep this last: */ NR_PHASES, }; +/* Each module should, in its CHILDPERSIST hooks, close all fds which + constitute ownership of important operating system resources, or + which are used for IPC with other processes who want to get the + usual disconnection effects if the main secnet process dies. + CHILDPERSIST hooks are not run if the child is going to exec; + so fds such as described above should be CLOEXEC too. */ + typedef void hook_fn(void *self, uint32_t newphase); bool_t add_hook(uint32_t phase, hook_fn *f, void *state); bool_t remove_hook(uint32_t phase, hook_fn *f, void *state); @@ -240,12 +314,20 @@ bool_t remove_hook(uint32_t phase, hook_fn *f, void *state); extern uint32_t current_phase; extern void enter_phase(uint32_t new_phase); +void phase_hooks_init(void); /* for main() only */ +void clear_phase_hooks(uint32_t phase); /* for afterfork() */ + /* Some features (like netlink 'soft' routes) require that secnet retain root privileges. They should indicate that here when appropriate. */ extern bool_t require_root_privileges; extern cstring_t require_root_privileges_explanation; +/* Some modules may want to know whether secnet is going to drop + privilege, so that they know whether to do privsep. Call only + in phases SETUP and later. */ +bool_t will_droppriv(void); + /***** END of program lifetime support *****/ /***** MODULE support *****/ @@ -260,6 +342,7 @@ extern void init_builtin_modules(dict_t *dict); extern init_module resolver_module; extern init_module random_module; extern init_module udp_module; +extern init_module polypath_module; extern init_module util_module; extern init_module site_module; extern init_module transform_eax_module; @@ -355,8 +438,17 @@ struct comm_addr { int ix; /* see comment `Re comm_addr.ix' in udp.c */ }; +struct comm_clientinfo; /* private for comm */ + +typedef struct comm_clientinfo *comm_clientinfo_fn(void *state, dict_t*, + struct cloc cloc); +/* A comm client may call this during configuration, and then pass + * the resulting comm_clientinfo* to some or all sendmsg calls. + * The semantics depend on the dict and defined by the comm, and + * should be documented in README. */ + /* Return True if the packet was processed, and shouldn't be passed to - any other potential receivers. */ + any other potential receivers. (buf is freed iff True returned.) */ typedef bool_t comm_notify_fn(void *state, struct buffer_if *buf, const struct comm_addr *source); typedef void comm_request_notify_fn(void *commst, void *nst, @@ -364,7 +456,8 @@ typedef void comm_request_notify_fn(void *commst, void *nst, typedef void comm_release_notify_fn(void *commst, void *nst, comm_notify_fn *fn); typedef bool_t comm_sendmsg_fn(void *commst, struct buffer_if *buf, - const struct comm_addr *dest); + const struct comm_addr *dest, + struct comm_clientinfo* /* 0 OK */); /* Only returns false if (we know that) the local network * environment is such that this address cannot work; transient * or unknown/unexpected failures return true. */ @@ -373,13 +466,15 @@ typedef const char *comm_addr_to_string_fn(void *commst, /* Returned string is in a static buffer. */ struct comm_if { void *st; + comm_clientinfo_fn *clientinfo; comm_request_notify_fn *request_notify; comm_release_notify_fn *release_notify; comm_sendmsg_fn *sendmsg; comm_addr_to_string_fn *addr_to_string; }; -bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib); +bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib, + bool_t ignoreport); static inline const char *comm_addr_to_string(const struct comm_addr *ca) { @@ -389,7 +484,7 @@ static inline const char *comm_addr_to_string(const struct comm_addr *ca) static inline bool_t comm_addr_equal(const struct comm_addr *a, const struct comm_addr *b) { - return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia); + return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia,False); } /* LOG interface */ @@ -448,13 +543,21 @@ typedef bool_t transform_setkey_fn(void *st, uint8_t *key, int32_t keylen, typedef bool_t transform_valid_fn(void *st); /* 0: no key; 1: ok */ typedef void transform_delkey_fn(void *st); typedef void transform_destroyinstance_fn(void *st); -/* Returns: - * 0: all is well - * 1: for any other problem - * 2: message decrypted but sequence number was out of range - */ -typedef uint32_t transform_apply_fn(void *st, struct buffer_if *buf, - const char **errmsg); + +typedef enum { + transform_apply_ok = 0, /* all is well (everyone may assume==0) */ + transform_apply_err = 1, /* any other problem */ + transform_apply_seqrange = 2, + /* message decrypted but sequence number was out of range */ +} transform_apply_return; + +static inline bool_t +transform_apply_return_badseq(transform_apply_return problem) { + return problem == transform_apply_seqrange; +} + +typedef transform_apply_return transform_apply_fn(void *st, + struct buffer_if *buf, const char **errmsg); struct transform_inst_if { void *st; @@ -565,6 +668,19 @@ extern NORETURN(fatal_status(int status, const char *message, ...)) extern NORETURN(fatal_perror_status(int status, const char *message, ...)) FORMAT(printf,2,3); +/* Convenient nonfatal logging. Requires message that does not end in '\n'. + * If class contains M_FATAL, exits (after entering PHASE_SHUTDOWN). + * lg, errnoval and loc may sensibly be 0. desc must NOT be 0. + * lg_[v]perror save and restore errno. */ +void lg_vperror(struct log_if *lg, const char *desc, struct cloc *loc, + int class, int errnoval, const char *fmt, va_list al) + FORMAT(printf,6,0); +void lg_perror(struct log_if *lg, const char *desc, struct cloc *loc, + int class, int errnoval, const char *fmt, ...) + FORMAT(printf,6,7); +void lg_exitstatus(struct log_if *lg, const char *desc, struct cloc *loc, + int class, int status, const char *progname); + /* The cfgfatal() family of functions require messages that end in '\n' */ extern NORETURN(cfgfatal(struct cloc loc, cstring_t facility, const char *message, ...)) FORMAT(printf,3,4);