/* wydawca - automatic release submission daemon Copyright (C) 2007, 2008, 2009 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 #define obstack_chunk_alloc malloc #define obstack_chunk_free free #include "obstack.h" #include "error.h" #include "xalloc.h" #include "progname.h" #include "backupfile.h" #include "inttostr.h" #include "gconf.h" #include "gl_list.h" #include "wordsplit.h" #define gettext(s) s #define _(s) s #define N_(s) s #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 access_method_id { verify_method, /* Method for verification user's access to the project */ gpg_key_method, /* Method for retrieving the user public key */ project_owner_method, /* Method for retrieving the names and emails of the project owners */ user_data_method, /* Method for retrieving the user name and real name by his uid */ access_method_count }; enum access_method_type { method_none, /* Undefined or no method */ method_sql, /* Use SQL database */ method_builtin, /* Use built-in facilities */ method_external /* Invoke an external program */ }; struct access_method { enum access_method_id id; enum access_method_type type; /* Access method 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; }; /* File triplet */ struct file_triplet { char *name; /* Triplet base name */ gid_t gid; /* Owner GID */ struct file_info file[FILE_TYPE_COUNT]; /* Components */ const struct spool *spool; /* Owning spool */ 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 */ /* Special data for template formatting */ char *project; /* Triplet project name (if known) */ char *user; /* User name (if known) */ char **user_data; }; /* 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)->gid) struct virt_tab { int (*test_url) (mu_url_t url, gconf_locus_t *loc); int (*move_file) (struct file_triplet *trp, const struct spool *spool, enum file_type file_id, const char *reldir); int (*archive_file) (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name); int (*symlink_file) (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *wanted_src, const char *wanted_dst); int (*rmsymlink_file)(struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name); }; /* An upload spool. This structure contains all data necessary for releasing files from source to destination */ struct spool { char *tag; gl_list_t 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 access_method *access_method[access_method_count]; struct archive_descr archive; /* Archivation data */ struct notification *notification; }; 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, 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, MAX_EVENT }; enum notification_target { 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 *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 access_method *method, void *handle); void meta_free (struct metadef *def); /* Global variables */ 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 *pidfile; extern int force_startup; extern char *lockdir; extern time_t lock_expire_time; unsigned lock_retry_attempts; time_t lock_retry_interval; extern int enable_locking; extern int daemon_mode; extern time_t wakeup_interval; extern int foreground; extern int single_process; extern struct gconf_sockaddr listen_sockaddr; extern gl_list_t all_spool_aliases; #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); 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_method_query (struct access_method *method, void *handle, struct file_triplet *trp); /* General-purpose method support */ struct access_method *method_new (enum access_method_id id, enum access_method_type type); int method_init (struct access_method *method); int method_done (struct access_method *method); void *method_open (struct access_method *method); int method_close (struct access_method *method, void *handle); int method_run (struct access_method *method, void *handle, const char *cmd); void method_copy_result (struct access_method *method, const char *res, size_t size); const char *method_result (struct access_method *method, void *handle, unsigned nrow, unsigned ncol); int method_quote_string (struct access_method *method, void *handle, const char *input, char **poutput, size_t *psize); unsigned method_num_rows (struct access_method *method); unsigned method_num_cols (struct access_method *method); /* Verification functions */ int verify_directive_file (struct file_triplet *trp, const struct spool *spool); int verify_directive_signature (struct file_triplet *trp, const struct spool *spool, const char *pubkey); int verify_detached_signature (struct file_triplet *trp, const struct spool *spool); int fill_project_name (struct file_triplet *trp); /* 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, const struct spool *spool); int enabled_spool_p (const struct spool *spool); int parse_time_interval (const char *str, time_t *pint, const char **endp); /* config.c */ void config_init (void); void config_help (void); int assert_string_arg (gconf_locus_t *, enum gconf_callback_command, const gconf_value_t *); /* vtab.c */ int url_to_vtab (mu_url_t url, struct virt_tab *vtab); int move_file (struct file_triplet *trp, const struct spool *spool, enum file_type file_id, const char *reldir); int archive_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name); int symlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *wanted_src, const char *wanted_dst); int rmsymlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name); /* diskio.c */ int dir_test_url (mu_url_t url, gconf_locus_t *locus); int dir_move_file (struct file_triplet *trp, const struct spool *spool, enum file_type file_id, const char *reldir); int dir_archive_file (struct file_triplet *trp, const struct spool *spool, const char *file_name, const char *reldir); int dir_symlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *wanted_src, const char *wanted_dst); int dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name); /* null.c */ int null_move_file (struct file_triplet *trp, const struct spool *spool, enum file_type file_id, const char *reldir); int null_archive_file (struct file_triplet *trp, const struct spool *spool, const char *file_name, const char *reldir); int null_symlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *wanted_src, const char *wanted_dst); int null_rmsymlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, 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); #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 gconf_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);