/* wydawca - automatic release submission daemon Copyright (C) 2007, 2008, 2009, 2010 Sergey Poznyakoff This program 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. This program 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 this program. 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 "error.h" #include "xalloc.h" #include "backupfile.h" #include "grecs.h" #include "wordsplit.h" #define SP(s) ((s) ? (s) : "NONE") #define WYDAWCA_EX_AGAIN 1 /* The range of directive versions we accept (major * 100 + minor) */ #define MIN_DIRECTIVE_VERSION 101 #define MAX_DIRECTIVE_VERSION 101 /* Default modes for mkdir and creat commands: rely on the umask value */ #define MKDIR_PERMISSIONS 0777 #define CREAT_PERMISSIONS 0666 #define SUF_SIG ".sig" #define SUF_SIG_LEN (sizeof (SUF_SIG) - 1) #define SUF_DIR ".directive.asc" #define SUF_DIR_LEN (sizeof (SUF_DIR) - 1) #define __cat2__(a,b) a ## b #define __cat3__(a,b,c) a ## b ## c #define NITEMS(a) (sizeof(a)/sizeof((a)[0])) enum dictionary_id { project_uploader_dict, /* Contains names, gpg-keys, emails and real names of the project uploaders */ project_owner_dict, /* Contains names and emails of the project owners */ dictionary_count }; enum dictionary_type { dictionary_none, /* Undefined or no dictionary */ dictionary_sql, /* Use SQL database */ dictionary_builtin, /* Use built-in facilities */ dictionary_external /* Invoke an external program */ }; struct dictionary { enum dictionary_id id; enum dictionary_type type; /* Dictionary type */ char *query; /* Query template */ int parmc; /* Number of entries in paramv */ char **parmv; /* Parameters. The semantics differs depending on type. For SQL: 0 - Identifier of the SQL struct to use; */ int init_passed; /* Initialization count */ char *result; /* Result storage */ size_t result_size; /* Size of result */ unsigned ncol; /* Number of columns per row */ unsigned nrow; /* Number of rows */ void *storage; }; /* Archive types */ enum archive_type { archive_none, /* No archivation requested */ archive_directory, /* Archive by moving files to a separate directory hierarchy */ archive_tar /* Archive by appending to a tar file (tar -r) */ }; struct archive_descr { enum archive_type type; /* Archivation type */ char *name; /* Directory name if type==archive_directory, archive file name if type==archive_tar */ enum backup_type backup_type; /* Requested backup type if type == archive_directory */ }; /* Type of file in a triplet */ enum file_type { file_dist, /* Something to be distributed */ file_signature, /* Detached signature (.sig) */ file_directive, /* Directive (.directive.asc) */ }; #define FILE_TYPE_COUNT (file_directive+1) /* Part of a triplet */ struct file_info { enum file_type type; /* Part type */ char *name; /* File name */ unsigned root_len; /* Length of root part in name */ struct stat sb; }; struct uploader_info { struct uploader_info *next; char *name; char *realname; char *email; char *gpg_key; char *fpr; }; /* File triplet */ struct file_triplet { char *name; /* Triplet base name */ struct file_info file[FILE_TYPE_COUNT]; /* Components */ const struct spool *spool; /* Owning spool */ char *relative_dir; /* Directory relative to spool->dest_dir */ char **directive; /* Decoded directive pairs (key: value\0) */ char *blurb; /* Block of directives: directive[i] points here */ char *tmp; /* Temporary storage */ size_t tmpsize; /* Size of memory allocated in tmp */ struct txtacc *acc; /* Text accumulator for string allocation */ /* User data */ size_t uploader_count; struct uploader_info *uploader_list; struct uploader_info *uploader; /* Special data for template formatting */ char *project; /* Triplet project name (if known) */ int check_result; /* Result of external check */ char *check_diag; /* External check diagnostics */ }; /* Macros to access owner UID and GID. */ /* The directive file is always present in the triplet */ #define TRIPLET_UID(t) ((t)->file[file_directive].sb.st_uid) /* GID is filled in after the triplet is finalized and verified */ #define TRIPLET_GID(t) ((t)->file[file_directive].sb.st_gid) struct virt_tab { int (*test_url) (mu_url_t url, grecs_locus_t *loc); int (*move_file) (struct file_triplet *trp, enum file_type file_id); int (*archive_file) (struct file_triplet *trp, const char *file_name); int (*symlink_file) (struct file_triplet *trp, const char *wanted_src, const char *wanted_dst); int (*rmsymlink_file)(struct file_triplet *trp, const char *file_name); }; /* An upload spool. This structure contains all data necessary for releasing files from source to destination */ struct spool { char *tag; struct grecs_list *aliases; char *url; /* Download URL */ char *source_dir; /* Source directory */ mu_url_t dest_url; /* Destination URL */ const char *dest_dir; /* Directory part of the above */ struct virt_tab vtab; /* Virtual method table */ time_t file_sweep_time; /* Remove invalid/unprocessed files after this amount of time */ struct dictionary *dictionary[dictionary_count]; struct archive_descr archive; /* Archivation data */ struct notification *notification; char *check_script; }; #define ASGN_SPOOL(spool, trp, faction) \ do \ { \ spool = (trp)->spool; \ if (!spool) \ { \ logmsg (LOG_CRIT, \ _("INTERNAL ERROR at %s:%d: spool not defined for %s"),\ __FILE__, __LINE__, (trp)->name); \ faction; \ } \ } \ while (0) enum wydawca_stat { STAT_ERRORS, STAT_WARNINGS, STAT_BAD_SIGNATURE, STAT_ACCESS_VIOLATIONS, STAT_COMPLETE_TRIPLETS, STAT_INCOMPLETE_TRIPLETS, STAT_BAD_TRIPLETS, STAT_EXPIRED_TRIPLETS, STAT_TRIPLET_SUCCESS, STAT_UPLOADS, STAT_ARCHIVES, STAT_SYMLINKS, STAT_RMSYMLINKS, STAT_CHECK_FAIL, MAX_STAT }; #define STAT_MASK(c) (1<<(c)) #define STAT_MASK_NONE 0 #define STAT_MASK_ALL (STAT_MASK(MAX_STAT) - 1) enum notification_event { ev_success, ev_bad_ownership, ev_bad_directive_signature, ev_bad_detached_signature, ev_check_fail, MAX_EVENT }; enum notification_target { notify_read, /* Read recipients from the message headers */ notify_admin, /* System administrator */ notify_owner, /* Project admin */ notify_user /* User (uploader) */ }; struct notification { struct notification *next; enum notification_event ev; enum notification_target tgt; const char *sign_keys; const char *msg; }; void register_message_template (const char *name, const char *text); void notify (struct notification *, struct file_triplet *, enum notification_event); const char *notification_event_str (enum notification_event evt); const char *notification_target_str (enum notification_target tgt); 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, struct dictionary *dict, void *handle); void meta_free (struct metadef *def); const char *expand_email_admin (struct metadef *def, void *data); const char *expand_email_owner (struct metadef *def, void *data); /* Global variables */ extern char *program_name; extern uid_t wydawca_uid; extern gid_t wydawca_gid; extern size_t wydawca_supp_groupc; extern gid_t *wydawca_supp_groups; extern char *conffile; /* Configuration file name */ extern int debug_level; /* Debugging level */ extern int dry_run_mode; /* Dry run indicator */ extern int log_to_stderr; /* Log to stderr instead of the syslog */ extern int log_facility; /* Syslog facility to use if !log_to_stderr */ extern char *syslog_tag; /* Syslog tag */ extern int syslog_include_prio;/* Syslog priority indication */ extern time_t file_sweep_time; /* Unlink stale file after this amount of time */ extern char *tar_command_name; /* Name of the tar command */ extern unsigned wydawca_stat[MAX_STAT]; extern unsigned long print_stats; extern int archive_signatures; extern char *admin_stat_message; extern char *admin_stat_sign_key; extern char *pidfile; extern int force_startup; extern char *lockdir; extern time_t lock_expire_time; extern time_t lock_timeout; extern int enable_locking; extern int daemon_mode; extern time_t wakeup_interval; extern int foreground; extern int single_process; extern struct grecs_sockaddr listen_sockaddr; extern struct grecs_list *all_spool_aliases; extern char *wydawca_gpg_homedir; extern char *default_check_script; extern char *temp_homedir; #define UPDATE_STATS(what) \ do \ { \ if (what >= MAX_STAT) abort(); \ wydawca_stat[what]++; \ } \ while (0) int stat_mask_p (unsigned long mask); struct metadef *make_stat_expansion (size_t count); void initstats (void); void logstats (void); /* Utility functions */ char *safe_file_name (char *file_name); char *safe_file_name_alloc (const char *file_name); size_t trim_length (const char *str); size_t trim (char *str); void logmsg (int prio, char *fmt, ...) GSC_PRINTFLIKE(2,3); int test_dir (const char *name, int *ec); char *create_directory (const char *base, const char *name); int create_hierarchy (char *dir, size_t baselen); void parse_config (void); void log_output (int prio, const char *prog, FILE *fp); enum exec_result { exec_success, /* Command executed and returned 0 */ exec_fail, /* Command executed and returned not 0 */ exec_error /* Command failed to execute */ }; enum exec_result wydawca_exec (int argc, const char **argv, int *retcode); /* Directory scanning and registering */ int scan_spool (const struct spool *spool, int uc, uid_t *uv); int scan_all_spools (int, uid_t *); void spool_create_timers (void); void register_spool (struct spool *spool); struct spool *wydawca_find_spool (const char *name); void register_file (struct file_info *finfo, const struct spool *spool); void enumerate_triplets (const struct spool *); size_t count_collected_triplets (void); char *triplet_expand_param (const char *tmpl, struct file_triplet *trp); char *triplet_expand_dictionary_query (struct dictionary *dict, void *handle, struct file_triplet *trp); /* General-purpose dictionary support */ struct dictionary *dictionary_new (enum dictionary_id id, enum dictionary_type type); int dictionary_init (struct dictionary *dict); int dictionary_done (struct dictionary *dict); void *dictionary_open (struct dictionary *dict); int dictionary_close (struct dictionary *dict, void *handle); int dictionary_lookup (struct dictionary *dict, void *handle, const char *cmd); void dictionary_copy_result (struct dictionary *dict, const char *res, size_t size); const char *dictionary_result (struct dictionary *dict, void *handle, unsigned nrow, unsigned ncol); int dictionary_quote_string (struct dictionary *dict, void *handle, const char *input, char **poutput, size_t *psize); unsigned dictionary_num_rows (struct dictionary *dict); unsigned dictionary_num_cols (struct dictionary *dict); /* Verification functions */ int verify_directive_file (struct file_triplet *trp); int verify_directive_signature (struct file_triplet *trp); int verify_detached_signature (struct file_triplet *trp); int fill_project_name (struct file_triplet *trp); struct uploader_info *uploader_find_frp (struct uploader_info *list, const char *frp); /* Directive file support */ int directive_parse (struct file_triplet *trp); int directive_get_value (struct file_triplet *trp, const char *key, const char **pval); int directive_pack_version (const char *val, unsigned *pversion); int directive_version_in_range_p (struct file_triplet *trp, unsigned from, unsigned to); int verify_directive_format (struct file_triplet *trp); int directive_first (struct file_triplet *trp, const char **pkey, const char **pval); int directive_next (struct file_triplet *trp, int n, const char **pkey, const char **pval); int process_directives (struct file_triplet *trp); int enabled_spool_p (const struct spool *spool); int selected_spools (void); char *triplet_strdup (struct file_triplet *tp, const char *str); int parse_time_interval (const char *str, time_t *pint, const char **endp); /* config.c */ void config_init (void); void config_finish (struct grecs_node *); void config_help (void); int assert_string_arg (grecs_locus_t *, enum grecs_callback_command, const grecs_value_t *); /* vtab.c */ int url_to_vtab (mu_url_t url, struct virt_tab *vtab); int move_file (struct file_triplet *trp, enum file_type file_id); int archive_file (struct file_triplet *trp, const char *file_name); int symlink_file (struct file_triplet *trp, const char *wanted_src, const char *wanted_dst); int rmsymlink_file (struct file_triplet *trp, const char *file_name); /* diskio.c */ char *concat_dir (const char *base, const char *name, size_t *pbaselen); int copy_file (const char *file, const char *dst_file); int dir_test_url (mu_url_t url, grecs_locus_t *locus); int dir_move_file (struct file_triplet *trp, enum file_type file_id); int dir_archive_file (struct file_triplet *trp, const char *reldir); int dir_symlink_file (struct file_triplet *trp, const char *wanted_src, const char *wanted_dst); int dir_rmsymlink_file (struct file_triplet *trp, const char *file_name); /* null.c */ int null_move_file (struct file_triplet *trp, enum file_type file_id); int null_archive_file (struct file_triplet *trp, const char *file_name); int null_symlink_file (struct file_triplet *trp, const char *wanted_src, const char *wanted_dst); int null_rmsymlink_file (struct file_triplet *trp, const char *file_name); /* timer.c */ typedef struct timer_slot *wydawca_timer_t; wydawca_timer_t timer_get (const char *name); wydawca_timer_t timer_start (const char *name); wydawca_timer_t timer_stop (const char *name); wydawca_timer_t timer_reset (const char *name); double timer_get_real (wydawca_timer_t t); double timer_get_user (wydawca_timer_t t); double timer_get_system (wydawca_timer_t t); char *timer_format_time (double t); size_t timer_get_count (void); void timer_fill_meta (struct metadef *def, size_t num); void timer_free_meta (struct metadef *def, size_t num); void report_init (void); void report_add (const char *fmt, ...); void report_finish (void); extern char *report_string; /* job.c */ void schedule_job (const struct spool *spool, uid_t uid); void job_init (void); void job_queue_runner (void); /* profile.c */ void check_pidfile (void); void remove_pidfile (void); /* net.c */ void wydawca_listener (void); void trim_crlf (char *s); #define LOCK_OK 0 #define LOCK_CONFLICT 1 #define LOCK_RETRY 2 #define LOCK_INVALID 3 #define LOCK_FAILURE 4 char *wydawca_lockname (const char *tag); int wydawca_lock (const char *lockname); void wydawca_unlock (const char *lockname); void wydawca_lock_init (void); /* tcpwrap.h */ extern struct grecs_keyword tcpwrapper_kw[]; int tcpwrap_access(int fd); /* userprivs.c */ int wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp); int push_dir (const char *dirname); int pop_dir (void); char *getcwd_alloc (void); struct txtacc *txtacc_create (void); void txtacc_free (struct txtacc *acc); void txtacc_free_string (struct txtacc *acc, char *str); void txtacc_grow (struct txtacc *acc, const char *buf, size_t size); #define txtacc_1grow(acc, c) \ do \ { \ char __ch = c; \ txtacc_grow (acc, &__ch, 1); \ } \ while (0) char *txtacc_finish (struct txtacc *acc);