/* This file is part of GNU Pies. Copyright (C) 2008, 2009, 2010, 2011 Sergey Poznyakoff GNU Pies 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, or (at your option) any later version. GNU Pies 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 GNU Pies. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "progname.h" #include "inttostr.h" #include "c-ctype.h" #include "xalloc.h" #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free #include "obstack.h" #include "xvasprintf.h" #include "quotearg.h" #include "fprintftime.h" #include "acl.h" #include "libpies.h" #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) #define TESTTIME 2*60 #define SLEEPTIME 5*60 #define MAXSPAWN 10 #define DEFAULT_PASS_FD_TIMEOUT 5 #define RETR_OUT 0 #define RETR_ERR 1 enum redir_type { redir_null, redir_syslog, redir_file }; struct redirector { enum redir_type type; union { int prio; char *file; } v; }; typedef struct limits_rec *limits_record_t; enum return_action { action_restart, action_disable, }; #define STATUS_SIG_BIT 0x80000000 #define STATUS_CODE(c) ((c) & ~STATUS_SIG_BIT) struct action { struct action *next; size_t nstat; unsigned *status; enum return_action act; /* Action to take when the component terminates */ char *addr; /* Addresses to notify about it. */ char *message; /* Notification mail. */ char *command; /* Execute this command */ }; /* user privs */ struct pies_privs { char *user; int allgroups; struct grecs_list *groups; }; enum pies_comp_mode { /* ** Pies native component types. */ /* Execute the component, no sockets are opened. This is the default Pies mode. */ pies_comp_exec, /* Open a socket and start a component with stdin/stdout bound to that socket. Corresponds to MeTA1 notion of `start_action = accept'. */ pies_comp_accept, /* Inetd mode: like above, but start the component only when an incoming connection is requested. Corresponds to `start_action = nostartaccept' in MeTA1. */ pies_comp_inetd, /* Open a socket, start a component, and pass the socket fd to the component via the UNIX domain socket. Corresponds to `start_action = pass' in MeTA1. */ pies_comp_pass_fd, /* ** Init-style components */ pies_mark_sysvinit, /* Start the process when the specified runlevel is entered and wait for its termination */ pies_comp_wait = pies_mark_sysvinit, /* Execute the component once, when the specified runlevel is entered */ pies_comp_once, /* Execute the component during system boot. Ignore runlevel settings. */ pies_comp_boot, /* Execute the component during system boot and wait for it to terminate. Ignore runlevel settings. */ pies_comp_bootwait, /* Execute the component when the power goes down. */ pies_comp_powerfail, /* Execute the component when the power goes down. Wait for it to terminate. */ pies_comp_powerwait, /* Execute the component when the power is restored. Wait for it to terminate. */ pies_comp_powerokwait, /* Execute the process when SIGINT is delivered, i.e. someone has pressed the Ctrl+Alt+Del combination. */ pies_comp_ctrlaltdel, /* Execute the component when a specified ondemand runlevel is called */ pies_comp_ondemand, /* Execute the component on the system boot. */ pies_comp_sysinit, /* Execute the component when running on the UPS and pies is informed that the UPS battery is almost empty. */ pies_comp_powerfailnow, /* Execute the component a signal from the keyboard handler arrives, indicating that a special key combination was pressed on the console keyboard. */ pies_comp_kbrequest, /* Restart the component wherever it terminates */ pies_comp_respawn = pies_comp_exec, }; #define is_sysvinit(m) ((m)>=pies_mark_sysvinit) #define CF_DISABLED 0x001 /* The componenet is disabled */ #define CF_PRECIOUS 0x002 /* The component is precious (should not be disabled) */ #define CF_WAIT 0x004 /* Wait for the component instance to terminate. */ #define CF_TCPMUX 0x008 /* A plain TCPMUX service */ #define CF_TCPMUXPLUS 0x010 /* A TCPMUX-plus service, i.e. pies must emit a '+' response before starting it */ #define CF_INTERNAL 0x020 /* An internal inetd service */ #define CF_SOCKENV 0x040 /* Component wants socket information in the environment */ #define CF_RESOLVE 0x080 /* Resolve IP addresses */ #define CF_SIGGROUP 0x100 /* Send signals to the process group */ #define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS)) struct component { enum pies_comp_mode mode; char *tag; /* Entry tag (for diagnostics purposes) */ char *program; /* Program name */ size_t argc; /* Number of command line arguments */ char **argv; /* Program command line */ char **env; /* Program environment */ char *dir; /* Working directory */ struct grecs_list *prereq; /* Prerequisites */ struct grecs_list *depend; /* Dependency targets */ int flags; /* CF_ bitmask */ size_t max_instances; /* Maximum number of simultaneously running instances */ char *rmfile; /* Try to remove this file before starting */ struct pies_privs privs; /* UID/GIDS+groups to run under */ mode_t umask; /* Umask to install before starting */ limits_record_t limits; /* System limits */ /* For exec (init) components */ char *runlevels; /* For inetd components */ size_t max_rate; /* Maximum number of invocations per minute */ size_t max_ip_connections; /* Max. number of connections per IP address */ int socket_type; /* Socket type */ struct inetd_builtin *builtin; /* Builtin function */ char *service; struct pies_url *socket_url; /* Socket to listen on (if mode != pies_comp_exec) */ char *pass_fd_socket; /* Socket to pass fd on (if mode == pies_comp_pass_fd) */ unsigned pass_fd_timeout; /* Maximum time to wait for pass_fd socket to become available. */ pies_acl_t acl; char *tcpmux; /* Master service for TCPMUX */ /* Optional error messages to be sent back on the socket: */ char *access_denied_message; char *max_instances_message; char *max_ip_connections_message; /* Redirectors: */ int facility; /* Syslog facility. */ struct redirector redir[2]; /* Repeaters for stdout and stderr */ /* Actions to execute on various exit codes: */ struct action *act_head, *act_tail; struct action act_temp; /* Auxiliary object used during configuration */ }; union pies_sockaddr_storage { struct sockaddr s; struct sockaddr_in s_in; struct sockaddr_un s_un; }; extern char *log_tag; extern int log_facility; extern unsigned long shutdown_timeout; extern struct component default_component; extern pies_acl_t pies_acl; extern limits_record_t pies_limits; extern char *mailer_program; extern char *mailer_command_line; extern int mailer_argc; extern char **mailer_argv; extern size_t default_max_rate; extern char *qotdfile; extern int init_process; extern char *console_device; extern int initdefault; extern int dfl_level; void register_prog (struct component *comp); int progman_running_p (void); size_t progman_running_count (void); void progman_start (void); void progman_wake_sleeping (int); void progman_stop (void); void progman_cleanup (int expect_term); void progman_stop_component (const char *name); void progman_dump_stats (const char *filename); void progman_dump_prereq (void); void progman_dump_depmap (void); int progman_accept (int socket); int progman_build_depmap (void); void progman_create_sockets (void); struct component *progman_lookup_component (const char *tag); struct component *progman_lookup_tcpmux (const char *service, const char *master); void progman_run_comp (struct component *comp, int fd, union pies_sockaddr_storage *sa, socklen_t salen); void progman_iterate_comp (int (*fun) (struct component *, void *), void *data); void fd_report (int fd, const char *msg); int check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen); void log_setup (int want_stderr); void signal_setup (RETSIGTYPE (*sf)(int)); typedef struct pies_depmap *pies_depmap_t; typedef struct pies_depmap_pos *pies_depmap_pos_t; enum pies_depmap_direction { depmap_row = 0, depmap_col = !depmap_row }; pies_depmap_t depmap_alloc (size_t count); pies_depmap_t depmap_copy (pies_depmap_t dpm); void depmap_set (pies_depmap_t dmap, size_t row, size_t col); int depmap_isset (pies_depmap_t dmap, size_t row, size_t col); void depmap_tc (pies_depmap_t dmap); size_t depmap_first (pies_depmap_t dmap, enum pies_depmap_direction dir, size_t coord, pies_depmap_pos_t *ppos); size_t depmap_next (pies_depmap_t dmap, pies_depmap_pos_t pos); int assert_grecs_value_type (grecs_locus_t *locus, const grecs_value_t *value, int type); int str_to_socket_type (const char *str, int *pret); int socket_type_to_str (int socket_type, const char **pres); struct component *component_create (const char *name); void component_finish (struct component *comp, grecs_locus_t *locus); struct grecs_keyword *find_component_keyword (const char *ident); /* url.c */ struct pies_url { char *string; char *scheme; char *host; char *port_s; int port; char *proto_s; int proto; char *path; char *user; char *passwd; int argc; char **argv; }; int pies_url_create (struct pies_url **purl, const char *str); void pies_url_destroy (struct pies_url **purl); const char * pies_url_get_arg (struct pies_url *url, const char *argname); void pies_pause (void); int register_socket (int socktype, int fd); int pass_fd (const char *socket, int fd, unsigned time_out); int create_socket (struct pies_url *url, int socket_type, const char *user, mode_t umask); void disable_socket (int fd); void enable_socket (int fd); int parse_limits (limits_record_t *plrec, char *str, char **endp); int set_limits (const char *name, limits_record_t lrec); void meta1_parser_set_debug (void); int meta1lex (void); int meta1error (char *s); int meta1parse (void); /* diag.c */ #define DIAG_TO_SYSLOG 0x1 #define DIAG_TO_STDERR 0x2 extern int diag_output; #define DIAG_OUTPUT(x) (diag_output & (x)) void diag_setup (int flags); void logmsg (int prio, const char *fmt, ...); void logmsg_printf (int prio, const char *fmt, ...); void logmsg_vprintf (int prio, const char *fmt, va_list ap); extern unsigned debug_level; extern int source_info_option; void debug_msg (const char *fmt, ...); #define debug(lev, args) \ do \ if (debug_level >= lev) \ { \ if (source_info_option) \ logmsg_printf (LOG_DEBUG, "%s:%lu:%s: ", \ __FILE__, __LINE__, __FUNCTION__); \ debug_msg args; \ } \ while (0) /* meta.c */ struct metadef { char *kw; char *value; const char *(*expand) (struct metadef *, void *); char *storage; void *data; }; char *meta_expand_string (const char *string, struct metadef *def, void *data); void meta_free (struct metadef *def); /* addrfmt.c */ void sockaddr_to_str (const struct sockaddr *sa, int salen, char *bufptr, size_t buflen, size_t *plen); char *sockaddr_to_astr (const struct sockaddr *sa, int salen); /* userprivs.c */ int switch_to_privs (uid_t uid, gid_t gid, struct grecs_list *retain_groups); void pies_priv_setup (struct pies_privs *); void pies_epriv_setup (struct pies_privs *); /* inetd.c */ int inetd_parse_conf (const char *file); /* inetd-bi.c */ struct inetd_builtin { const char *service; int socktype; int single_process; int flags; void (*fun) (int, struct component const *); }; struct inetd_builtin *inetd_builtin_lookup (const char *service, int socktype); /* sysvinit.c */ int runlevel_match (struct component *comp); void inittrans (void); int is_comp_wait (struct component *comp);