aboutsummaryrefslogtreecommitdiff
path: root/src/wydawca.h
blob: fd0bbfbe5074ca8fd11d8b5f7facbd8564e1632e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
/* wydawca - automatic release submission daemon
   Copyright (C) 2007-2013, 2017, 2019-2020 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 <http://www.gnu.org/licenses/>. */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <syslog.h>
#include <getopt.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <time.h>
#include <sysexits.h>
#include <fnmatch.h>
#include <regex.h>

#include <mailutils/types.h>
#include <mailutils/errno.h>

#include <wydawca/wydawca.h>

#include "grecs.h"
#include "wordsplit.h"

#ifndef O_SEARCH
# define O_SEARCH 0
#endif

#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 102

/* 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 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;
};

enum backup_type {
    no_backups,			/* Don't make backups */
    simple_backups,		/* Make only simple backups */
    numbered_existing_backups,	/* Make numbered backups for files that
				   already have such backups and simple
				   backups for the rest */
    numbered_backups,		/* Make only numbered backups */
};

extern char const *simple_backup_suffix;

char *find_backup_file_name(char const *, enum backup_type);
const char *split_filename(char const *file, char **pdir);

#define METADATA_NONE  0
#define METADATA_MODE  0x1
#define METADATA_OWNER 0x2

struct directory_metadata {
    int flags;
    mode_t mode;
    uid_t uid;
    gid_t gid;
};

/* 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 */
    struct directory_metadata metadata;	/* Directory metadata */
};

/* 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 wy_triplet {
    char *name;			/* Triplet base name */
    struct file_info file[FILE_TYPE_COUNT];	/* Components */
    unsigned version;		/* Protocol version */
    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 grecs_txtacc *acc;	/* Text accumulator for string allocation */
    /* Triplets are joined in two doubly-linked lists:
       1) a cronological list, with prev pointing to a triplet older
       than this one, and next pointing to a triplet newer than it: */
    struct wy_triplet *prev, *next;
    /* 2) "job queue", a list of triplets processed by the same job: */
    struct wy_triplet *jq_prev, *jq_next;
    /* The job queue is used only when triplets are processed by
       the inotify watcher.  In that case, the job member points to
       the job processing this request.  When the job terminates, all
       requests belonging to it are removed from the table to avoid them
       being processed by subsequent jobs.
       If started as a cron job, or awoken by a TCP listener, both
       job and jq_prev, jq_next are NULL. */
    struct job *job;
    /* User data */
    struct wy_user *uploader_list;
    struct wy_user *uploader;
    /* Admin data */
    struct wy_user *admin_list;
    /* 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)

typedef struct wy_url *wy_url_t;

wy_url_t wy_url_create(const char *str);
void wy_url_free(wy_url_t url);
const char *wy_url_path(wy_url_t url);
const char *wy_url_scheme(wy_url_t url);
const char *wy_url_printable(wy_url_t url);
int wy_url_is_local(wy_url_t url);

struct virt_tab {
    int (*test_url) (wy_url_t url, grecs_locus_t * loc);
    int (*move_file) (struct wy_triplet * trp, enum file_type file_id);
    int (*archive_file) (struct wy_triplet * trp, const char *file_name);
    int (*symlink_file) (struct wy_triplet * trp,
			 const char *wanted_src, const char *wanted_dst);
    int (*rmsymlink_file) (struct wy_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 */
    int source_fd;		/* File handle of the source directory */
    struct directory_metadata source_metadata;
    wy_url_t dest_url;		/* Destination URL */
    const char *dest_dir;	/* Directory part of the above */
    struct directory_metadata dest_metadata;
    struct virt_tab vtab;	/* Virtual method table */
    int inotify_enable;

    time_t file_sweep_time;	/* Remove invalid/unprocessed files
				   after this amount of time */
    struct dictionary *dictionary[dictionary_count];
    int dict_inited;
    struct archive_descr archive;	/* Archivation data */
    struct notification *notification;
    char *check_script;
};

#define ASGN_SPOOL(spool, trp, faction) do {				\
		spool = (trp)->spool;					\
		if (!spool) {						\
			wy_log (LOG_CRIT,				\
				_("INTERNAL ERROR at %s:%d: "		\
				  "spool not defined for %s"),		\
				__FILE__, __LINE__, (trp)->name);	\
			faction;					\
		}							\
	} while (0)

struct notification {
    struct notification *next;
    enum wy_event ev;
    char *modname;
    void *modcfg;
    grecs_node_t *modnode;
};

void notify(struct notification *, struct wy_triplet *, enum wy_event);
void notify_stats(void);
void notify_flush(struct spool *sp);
void notify_finish(void);


/* Modules */

struct module {
    struct module *next;
    char *name;
    char *path;
    grecs_locus_t locus;
    grecs_node_t *modinit;
    void *handle;
    int (*open) (grecs_node_t *);
    void *(*config) (grecs_node_t *);
    int (*notify) (void *, int, struct wy_triplet *);
    void (*flush) (void *);
    void (*close) (void);
};

int cb_module(enum grecs_callback_command cmd, grecs_node_t * node,
	      void *varptr, void *cb_data);
void modules_load(void);
void modules_close(void);
void modules_help(void);

int module_set_init(const char *name, grecs_node_t * node);

extern struct grecs_list *module_load_path, *module_prepend_load_path;
void module_notify(const char *name, void *modcfg,
		   enum wy_event ev, struct wy_triplet *tpl);
void module_flush(const char *name, void *modcfg);
void module_help(const char *modname);

/* 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 int wydawca_runas;
extern char *conffile;		/* Configuration file name */
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[WY_MAX_STAT];
extern unsigned long print_stats;
extern int archive_signatures;

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;

enum {
    WY_MODE_NORMAL,
    WY_MODE_CRON,
    WY_MODE_DAEMON,
};
extern int wy_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 *default_check_script;
extern char *temp_homedir;

extern unsigned min_directive_version;
extern unsigned max_directive_version;

extern int inotify_enable;

extern struct notification *default_notification;

#define UPDATE_STATS(what) do {			\
		if (what >= WY_MAX_STAT) abort();	\
		wydawca_stat[what]++;		\
	} while (0)

int stat_mask_p(unsigned long mask);
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);

int test_dir(const char *name, int *ec);
char *create_directory(const char *base, const char *name);
int create_hierarchy(char const *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(struct spool *spool, int uc, uid_t * uv);
int scan_all_spools(int, uid_t *);
void spool_create_timers(void);

int spool_add_new_file(const struct spool *spool, const char *name,
		       int uc, uid_t * uv);
int spool_open_dictionaries(struct spool *spool);
void spool_close_dictionaries(struct spool *spool);

void parse_file_name(const char *name, struct file_info *finfo);
void file_info_cleanup(struct file_info *finfo);
int for_each_spool(int (*fun) (struct spool *, void *), void *data);
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 spool_commit_triplets(struct spool *, struct wy_triplet *);
struct wy_triplet *link_processable_triplets(void);
size_t count_collected_triplets(void);

char *triplet_expand_dictionary_query(struct dictionary *dict,
				      void *handle,
				      struct wy_triplet *trp);

void triplet_remove_file(struct spool *spool, const char *name);

time_t triplet_sweep(void);
int remove_triplet(struct wy_triplet *trp, int check);

/* 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);

void dictionaries_close(void);

/* Verification functions */
int verify_directive_file(struct wy_triplet *trp, int noath);
int verify_directive_signature(struct wy_triplet *trp);
int verify_detached_signature(struct wy_triplet *trp);
int fill_project_name(struct wy_triplet *trp);
struct wy_user *uploader_find_frp(struct wy_user *list, const char *frp);

/* Directive file support */
int directive_parse(struct wy_triplet *trp);
int directive_get_value(struct wy_triplet const *trp, const char *key,
			const char **pval);
int directive_pack_version(const char *val, unsigned *pversion);
int directive_unpack_version(unsigned version, char **pbuf,
			     size_t * psize);

int directive_version_in_range_p(struct wy_triplet *trp,
				 unsigned from, unsigned to);
int verify_directive_format(struct wy_triplet *trp);
int directive_first(struct wy_triplet *trp, const char **pkey,
		    const char **pval);
int directive_next(struct wy_triplet *trp, int n,
		   const char **pkey, const char **pval);
int process_directives(struct wy_triplet *trp);

int enabled_spool_p(const struct spool *spool);
int selected_spools(void);

char *triplet_strdup(struct wy_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 wy_assert_string_arg(grecs_locus_t *, enum grecs_callback_command,
			 const grecs_value_t *);
grecs_value_t *get_arg(grecs_value_t * value, unsigned n, int type);

int wy_strtofac(const char *str);
int wy_strtopri(const char *str);
const char *wy_pritostr(int pri);
const char *wy_factostr(int fac);


/* vtab.c */
int url_to_vtab(wy_url_t url, struct virt_tab *vtab);

int move_file(struct wy_triplet *trp, enum file_type file_id);
int archive_file(struct wy_triplet *trp, const char *file_name);
int symlink_file(struct wy_triplet *trp,
		 const char *wanted_src, const char *wanted_dst);
int rmsymlink_file(struct wy_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(wy_url_t url, grecs_locus_t * locus);
int dir_move_file(struct wy_triplet *trp, enum file_type file_id);
int dir_archive_file(struct wy_triplet *trp, const char *reldir);
int dir_symlink_file(struct wy_triplet *trp,
		     const char *wanted_src, const char *wanted_dst);
int dir_rmsymlink_file(struct wy_triplet *trp, const char *file_name);

/* null.c */
int null_move_file(struct wy_triplet *trp, enum file_type file_id);
int null_archive_file(struct wy_triplet *trp, const char *file_name);
int null_symlink_file(struct wy_triplet *trp,
		      const char *wanted_src, const char *wanted_dst);
int null_rmsymlink_file(struct wy_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 report_init(void);
void report_add(const char *fmt, ...);
void report_finish(void);
extern char *report_string;

/* job.c */
/* Wydawca job types */
enum job_type {
    JOB_TRIPLET,		/* Process a list of complete triplets */
    JOB_SPOOL,			/* Scan single spool */
    JOB_ALL_SPOOLS		/* Scan all spools */
};

struct job_spool_id {
    struct spool *spool;
    uid_t uid;
};

void job_schedule(int type, void *data);

static inline void
job_schedule_all(void)
{
    job_schedule(JOB_ALL_SPOOLS, NULL);
}

static inline void
job_schedule_triplet(struct wy_triplet *tp)
{
    job_schedule(JOB_TRIPLET, tp);
}

static inline void
job_schedule_spool(struct spool *spool, uid_t uid)
{
    struct job_spool_id jid;
    jid.spool = spool;
    jid.uid = uid;
    job_schedule(JOB_SPOOL, &jid);
}

void job_init(void);
void job_queue_runner(time_t min_timeout);
void triplet_jq_unlink(struct wy_triplet *tp);

/* 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);

#ifdef WITH_INOTIFY
int watcher_init(void);
int watcher_run(int);
#else
# define watcher_init() -1
# define watcher_run(c)
#endif

int wy_stat_expansion(char **ret, char const *name, size_t len);
FILE *fopenat_ro(int dirfd, char const *name);

Return to:

Send suggestions and report system problems to the System administrator.