summaryrefslogtreecommitdiffabout
path: root/src/wydawca.h
blob: cb29ebc1040b3326f57f605338de091e1afd9082 (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
/* 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 <gpgme.h>
#include <pthread.h>

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

#include <wydawca/wydawca.h>

#include "grecs.h"
#include "wordsplit.h"
#include "queue.h"
#include "micron.h"

#ifndef O_SEARCH
# define O_SEARCH 0
#endif

void wy_set_cur_thread_name(char const *name);

#define SP(s) ((s) ? (s) : "NONE")

#define DEFAULT_FILE_SWEEP_TIME 300
#define DEFAULT_STAT_REPORT_INTERVAL 3600

/* 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(int, 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;
};

/* Values for the triplet directive_verified member */
enum {
    DIRECTIVE_UNCHECKED = -1,
    DIRECTIVE_GOOD = 0,
    DIRECTIVE_BAD = 1
};

/* File triplet */
struct wy_triplet {
    char *name;			/* Triplet base name */
    struct file_info file[FILE_TYPE_COUNT];	/* Components */
    unsigned version;		/* Protocol version */
    int directive_verified;     /* Directive file verification result */
    int replace_allowed;        /* Is replacing of the existing files allowed */
    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 */
    struct grecs_txtacc *report_acc;/* Text accumulator for reports */
    char *report_str;               /* Final report string */
    /* Triplets are joined in a doubly-linked list in chronological order.
       The prev member points to a triplet older than this one, and next
       points to a triplet newer than it: */
    TAILQ_ENTRY(wy_triplet) link;
    struct triplet_list *list;
    int in_processing;          /* True if the triplet is being processed */
    /* 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 */
    /* GPGME context */
    gpgme_ctx_t gpgme_ctx;
};

/* 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);
};

struct notification {
    STAILQ_ENTRY(notification) link;
    enum wy_event ev;
    char *modname;
    void *modcfg;
    grecs_node_t *modnode;
};

typedef STAILQ_HEAD(,notification) NOTIFYQ;
#define NOTIFYQ_INITIALIZER(name) STAILQ_HEAD_INITIALIZER(name)
#define NOTIFYQ_EMPTY(q) STAILQ_EMPTY(q)
#define NOTIFYQ_FOREACH(var, queue) STAILQ_FOREACH(var, queue, link)
#define NOTIFYQ_APPEND(queue, ntf) STAILQ_INSERT_TAIL(queue, ntf, link)
#define NOTIFYQ_INIT(queue) STAILQ_INIT(queue)

/* An upload spool. This structure contains all data necessary for releasing 
   files from source to destination */
struct spool {
    STAILQ_ENTRY(spool) link;
    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 */
    NOTIFYQ notification_queue;
    char *check_script;
};

void notify(const NOTIFYQ *, struct wy_triplet *, enum wy_event);
void spool_notify_flush(struct spool *sp);
void notify_stat(void);


/* Modules */

struct module {
    STAILQ_ENTRY(module) link;
    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 struct micronent stat_report_schedule;
extern char *tar_command_name;	/* Name of the tar command */
extern unsigned long print_stats;
extern int archive_signatures;

extern char *pidfile;
extern int force_startup;

enum {
    WY_MODE_NORMAL,
    WY_MODE_CRON,
    WY_MODE_DAEMON,
};
extern int wy_mode;

extern int foreground;
extern struct grecs_sockaddr listen_sockaddr;
extern size_t max_connections;
extern time_t idle_timeout;

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 NOTIFYQ default_notification;

extern size_t spool_count;

typedef unsigned WY_STAT_COUNTER;

void wydawca_stat_init(void);
void wydawca_stat_notify(int final);
void wydawca_stat_add(int what, size_t n);
static inline void
wydawca_stat_incr(int what)
{
    wydawca_stat_add(what, 1);
}


/* 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(int dirfd, char const *dir);
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);
void scan_all_spools(void);

struct wy_triplet *spool_add_new_file(struct spool *spool, const char *name);
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);
struct wy_triplet *register_file(struct file_info *finfo, struct spool *spool);

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

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

void remove_triplet(struct wy_triplet *trp);
void triplet_enqueue(struct wy_triplet *trp);
void triplet_commit(struct wy_triplet *trp);
void triplet_gpgme_ctx_release(struct wy_triplet *trp);

void triplet_report_add(struct wy_triplet *trp, const char *fmt, ...);
void triplet_report_finish(struct wy_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);

void dictionaries_close(void);

/* Verification functions */
int verify_directive_file(struct wy_triplet *trp);
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_file(char const *dir, ...);
int copy_file(int src_dirfd, const char *src_file,
	      int dst_dirfd, 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);

/* profile.c */
void pidfile_check(void);
void pidfile_remove(void);
void pidfile_update(void);

/* net.c */
void *wy_thr_listen(void *);
void trim_crlf(char *s);

/* 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);

#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);

void *wy_thr_triplet(void *ptr);
void *wy_thr_cleaner(void *ptr);
void wy_triplet_wait(void);
void *wy_thr_tcpmux(void *ptr);
void *wy_thr_connection_watcher(void *ptr);

Return to:

Send suggestions and report system problems to the System administrator.