aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/config.c54
-rw-r--r--src/directive.c42
-rw-r--r--src/diskio.c35
-rw-r--r--src/exec.c2
-rw-r--r--src/gpg.c80
-rw-r--r--src/method.c2
-rw-r--r--src/process.c2
-rw-r--r--src/sql.c11
-rw-r--r--src/sql.h2
-rw-r--r--src/triplet.c86
-rw-r--r--src/verify.c34
-rw-r--r--src/wydawca.c2
-rw-r--r--src/wydawca.h5
13 files changed, 262 insertions, 95 deletions
diff --git a/src/config.c b/src/config.c
index ae7c974..8c4afd1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@ static struct access_method default_gpg_key_method;
#define skip_ws(s) while (*(s) && isspace (*(s))) (s)++;
#define skip_word(s) while (*(s) && !isspace (*(s))) (s)++;
+/* Return a pointer to the next word from *PSTR. Advanse *PSTR to the beginning
+ of next word, or to the terminating \0, whichever comes first. */
static char *
get_word (char **pstr)
{
@@ -49,6 +51,8 @@ get_word (char **pstr)
return word;
}
+/* Convert a boolean from STR into its C representation. If STR is a valid
+ boolean, store the result in *PVAL and return 0. Otherwise, return 1 */
static int
get_bool (char *str, int *pval)
{
@@ -77,6 +81,7 @@ get_bool (char *str, int *pval)
/home/user/../smith --> /home/smith
/home/user/../.. --> /
+ ../file --> NULL
*/
char *
safe_file_name (char *file_name)
@@ -96,32 +101,49 @@ safe_file_name (char *file_name)
/* delete trailing delimiter if any */
if (len && file_name[len-1] == '/')
file_name[len-1] = 0;
-
- /* Eliminate any /../ */
+
+ /* Eliminate any ./ and /../ */
for (p = strchr (file_name, '.'); p; p = strchr (p, '.'))
{
- if (p > file_name && p[-1] == '/')
+ if (p[1] == '/' && (p == file_name || p[-1] == '/'))
{
- if (p[1] == '.' && (p[2] == 0 || p[2] == '/'))
+ char *q, *s;
+
+ s = p + 2;
+ q = p;
+ while ((*q++ = *s++))
+ ;
+ continue;
+ }
+ else if (p[1] == '.' && (p[2] == 0 || p[2] == '/'))
+ {
+ if (p == file_name)
+ return NULL;
+ if (p[-1] == '/')
/* found */
{
char *q, *s;
+ s = p + 2;
+
/* Find previous delimiter */
for (q = p-2; *q != '/' && q >= file_name; q--)
;
if (q < file_name)
- break;
+ {
+ q = file_name;
+ s++;
+ }
+
/* Copy stuff */
- s = p + 2;
p = q;
while ((*q++ = *s++))
;
continue;
}
}
-
+
p++;
}
@@ -134,10 +156,15 @@ safe_file_name (char *file_name)
return file_name;
}
+/* Same as safe_file_name, but returns an allocated copy. */
char *
safe_file_name_alloc (const char *file_name)
{
- return safe_file_name (xstrdup (file_name));
+ char *s = xstrdup (file_name);
+ char *ns = safe_file_name (s);
+ if (!ns)
+ free (s);
+ return ns;
}
@@ -329,6 +356,13 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data)
return;
}
dp->archive.name = safe_file_name (xstrdup (word));
+ if (!dp->archive.name)
+ {
+ file->error_msg (file->file_name, file->line,
+ "invalid archive name: %s", word);
+ file->error_count++;
+ return;
+ }
word = get_word (&val);
@@ -544,7 +578,7 @@ cfg_tar_program (gsc_config_file_t *file, char *kw, char *val, void *unused)
{
char *word = safe_file_name (get_word (&val));
- if (word[0] != '/')
+ if (!word || word[0] != '/')
{
file->error_msg (file->file_name, file->line,
"must be an absolute file name");
diff --git a/src/directive.c b/src/directive.c
index 0853552..6337a17 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
int
directive_parse (struct file_triplet *trp)
{
- size_t dcount, i;
+ size_t dcount, i, j;
char *p;
if (debug_level > 2)
@@ -36,27 +36,27 @@ directive_parse (struct file_triplet *trp)
trp->directive = xcalloc (dcount + 1, sizeof trp->directive[0]);
p = trp->blurb;
- for (i = 0; i < dcount; )
+ for (i = j = 0; i < dcount; i++)
{
- trp->directive[i] = p;
+ trp->directive[j] = p;
p = strchr (p, '\n');
if (p)
*p++ = 0;
- if (trim (trp->directive[i]) == 0) /* ignore empty lines */
+ if (trim (trp->directive[j]) == 0) /* ignore empty lines */
continue;
- if (strchr (trp->directive[i], ':') == NULL)
+ if (strchr (trp->directive[j], ':') == NULL)
{
logmsg (LOG_ERR, "%s: invalid line: %s",
- trp->file[file_directive].name, trp->directive[i]);
+ trp->file[file_directive].name, trp->directive[j]);
free (trp->directive);
trp->directive = NULL;
return 1;
}
- i++;
+ j++;
if (!p)
break;
}
- trp->directive[i] = NULL;
+ trp->directive[j] = NULL;
return 0;
}
@@ -325,12 +325,26 @@ process_directives (struct file_triplet *trp, struct directory_pair *dpair)
case directory_dir:
relative_dir = safe_file_name_alloc (val);
+ if (!relative_dir || relative_dir[0] == '/')
+ {
+ logmsg (LOG_ERR, "%s: invalid directive",
+ trp->file[file_directive].name);
+ return 1;
+ }
break;
case filename_dir:
- if (move_file (trp, dpair, file_dist, relative_dir)
- || move_file (trp, dpair, file_signature, relative_dir))
- return 1;
+ if (verify_detached_signature (trp, dpair) == 0)
+ {
+ if (move_file (trp, dpair, file_dist, relative_dir)
+ || move_file (trp, dpair, file_signature, relative_dir))
+ return 1;
+ }
+ else
+ {
+ logmsg (LOG_ERR, "invalid detached signature for %s", trp->name);
+ return 1;
+ }
break;
case version_dir:
@@ -372,8 +386,8 @@ process_directives (struct file_triplet *trp, struct directory_pair *dpair)
break;
case rmsymlink_dir:
- logmsg (LOG_CRIT, "%s: %s directive is not supported yet",
- trp->file[file_directive].name, key);
+ if (rmsymlink_file (trp, dpair, relative_dir, val))
+ return 1;
}
}
diff --git a/src/diskio.c b/src/diskio.c
index cb8df71..0c65792 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -24,11 +24,16 @@
# endif
#endif
-/* Return true if ARG is a sub-directory of DIR */
+/* Return true if ARG is NULL or is a sub-directory of DIR */
int
sub_dir_p (char *arg, char *dir)
{
- int dlen = strlen (dir);
+ int dlen;
+
+ if (!arg)
+ return 0;
+
+ dlen = strlen (dir);
return strlen (arg) > dlen
&& memcmp (dir, arg, dlen) == 0
@@ -518,19 +523,19 @@ symlink_file (struct file_triplet *trp, struct directory_pair *dpair,
}
src = safe_file_name_alloc (wanted_src);
- if (!sub_dir_p (src, dpair->dest_dir))
+ if (!src || src[0] == '/')
{
logmsg (LOG_ERR, "symlink source `%s' does not lie under `%s'",
- src, dpair->dest_dir);
+ wanted_src, dpair->dest_dir);
free (src);
return 1;
}
dst = safe_file_name_alloc (wanted_dst);
- if (!sub_dir_p (dst, dpair->dest_dir))
+ if (!dst || dst[0] == '/')
{
logmsg (LOG_ERR, "symlink destination `%s' does not lie under `%s'",
- dst, dpair->dest_dir);
+ wanted_dst, dpair->dest_dir);
free (src);
free (dst);
return 1;
@@ -559,11 +564,17 @@ symlink_file (struct file_triplet *trp, struct directory_pair *dpair,
if (rc == 0)
{
- rc = link (src, dst);
- if (rc)
- logmsg (LOG_ERR,
- "symlinking %s to %s in directory %s failed: %s",
- src, dst, dst_dir, strerror (errno));
+ if (chdir (dst_dir))
+ logmsg (LOG_ERR, "cannot change to %s: %s",
+ dst_dir, strerror (errno));
+ else
+ {
+ rc = symlink (src, dst);
+ if (rc)
+ logmsg (LOG_ERR,
+ "symlinking %s to %s in directory %s failed: %s",
+ src, dst, dst_dir, strerror (errno));
+ }
}
}
diff --git a/src/exec.c b/src/exec.c
index 7eb8883..1e4fbad 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
diff --git a/src/gpg.c b/src/gpg.c
index 8e67e63..f4cade4 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -147,6 +147,57 @@ wydawca_gpg_homedir ()
return 0;
}
+static int
+gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig)
+{
+ if (!sig)
+ return 0;
+
+ for (; sig; sig = sig->next)
+ {
+ const char *uid;
+ gpgme_key_t key;
+
+ if (gpgme_get_key (ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR)
+ uid = key->uids->uid;
+ else
+ uid = sig->fpr;
+
+ switch (gpg_err_code (sig->status))
+ {
+ case GPG_ERR_NO_ERROR:
+ if (debug_level)
+ logmsg (LOG_NOTICE, "Good signature from %s", uid);
+ break;
+
+ case GPG_ERR_BAD_SIGNATURE:
+ logmsg (LOG_ERR, "BAD signature from %s", uid);
+ return 0;
+
+ case GPG_ERR_NO_PUBKEY:
+ logmsg (LOG_ERR, "No public key");
+ return 0;
+
+ case GPG_ERR_NO_DATA:
+ logmsg (LOG_ERR, "No signature");
+ return 0;
+
+ case GPG_ERR_SIG_EXPIRED:
+ logmsg (LOG_ERR, "Expired signature from %s", uid);
+ return 0;
+
+ case GPG_ERR_KEY_EXPIRED:
+ logmsg (LOG_ERR, "Key expired (%s)", uid);
+ return 0;
+
+ default:
+ logmsg (LOG_ERR, "Unknown signature error");
+ return 0;
+ }
+ }
+ return 1;
+}
+
/* Verify the directive file from TRP using public key PUBKEY */
/* FIXME: dpair currently unused */
int
@@ -171,14 +222,23 @@ verify_directive_signature (struct file_triplet *trp,
ec = gpgme_op_verify (ctx, directive_data, NULL, plain);
if (ec == GPG_ERR_NO_ERROR)
{
- size = gpgme_data_seek (plain, 0, SEEK_END);
- gpgme_data_seek (plain, 0, SEEK_SET);
- trp->blurb = xmalloc (size + 1);
- gpgme_data_read (plain, trp->blurb, size);
- trp->blurb[size] = 0;
- gpgme_data_release (plain);
-
- rc = directive_parse (trp);
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+
+ result = gpgme_op_verify_result (ctx);
+ if (gpg_sig_ok_p (ctx, result->signatures))
+ {
+ size = gpgme_data_seek (plain, 0, SEEK_END);
+ gpgme_data_seek (plain, 0, SEEK_SET);
+ trp->blurb = xmalloc (size + 1);
+ gpgme_data_read (plain, trp->blurb, size);
+ trp->blurb[size] = 0;
+ gpgme_data_release (plain);
+
+ rc = directive_parse (trp);
+ }
+ else
+ rc = 1;
}
else
{
@@ -230,7 +290,7 @@ verify_detached_signature (struct file_triplet *trp,
return 0;
case exec_fail:
- logmsg (LOG_ERR, "bad detached signature for %s", trp->name);
+ logmsg (LOG_ERR, "BAD detached signature for %s", trp->name);
break;
case exec_error:
diff --git a/src/method.c b/src/method.c
index 433bf6a..45dea5a 100644
--- a/src/method.c
+++ b/src/method.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
diff --git a/src/process.c b/src/process.c
index 5452cd9..b7ead65 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
diff --git a/src/sql.c b/src/sql.c
index 5e3bae5..95c601a 100644
--- a/src/sql.c
+++ b/src/sql.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -17,6 +17,7 @@
#include "wydawca.h"
#include "sql.h"
+/* Singly-linked list of configured MySQL connections. */
struct sql_list
{
struct sql_list *next;
@@ -25,6 +26,7 @@ struct sql_list
static struct sql_list *sql_list;
+/* Append CONN to the end of sql_list */
void
sql_register_conn (struct sqlconn *conn)
{
@@ -34,6 +36,7 @@ sql_register_conn (struct sqlconn *conn)
sql_list = ent;
}
+/* Find a configured connection that has the given IDENT */
struct sqlconn *
sql_find_connection (const char *ident)
{
@@ -44,12 +47,14 @@ sql_find_connection (const char *ident)
return NULL;
}
+/* Return true if there exists a connection with the given IDENT */
int
sql_connection_exists_p (const char *ident)
{
return sql_find_connection (ident) != NULL;
}
+/* Initialize MySQL access method */
int
sql_init_method (struct access_method *method)
{
@@ -74,7 +79,8 @@ sql_init_method (struct access_method *method)
method->v.sqlconn = conn;
return 0;
}
-
+
+/* Finish the initialized MySQL access method */
int
sql_done_method (struct access_method *method)
{
@@ -82,6 +88,7 @@ sql_done_method (struct access_method *method)
return 0;
}
+/* Execute QUERY using the given access METHOD. Return 0 on success. */
int
sql_run_method (struct access_method *method, const char *query)
{
diff --git a/src/sql.h b/src/sql.h
index ef60ddc..d3b83d1 100644
--- a/src/sql.h
+++ b/src/sql.h
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
diff --git a/src/triplet.c b/src/triplet.c
index 3ecee29..b6b3ad2 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -106,23 +106,46 @@ triplet_expired_p (struct file_triplet *trp, time_t ttl)
return false;
}
-/* Return true if TRP is a complete and valid triplet */
-static bool
-valid_triplet_p (struct file_triplet *trp)
-{
- if (trp->file[file_dist].name
- && trp->file[file_signature].name
- && trp->file[file_directive].name)
+
+enum triplet_state
+ {
+ triplet_directive, /* Short triplet: only a directive is present,
+ but nothing more is required */
+ triplet_complete, /* A complete triplet: all three files are present
+ and have the same owner */
+ triplet_incomplete, /* Incomplete triplet: some files are missing */
+ triplet_bad, /* Bad triplet. Should be removed immediately. */
+ };
+
+
+static enum triplet_state
+check_triplet_state (struct file_triplet *trp)
+{
+ if (trp->file[file_directive].name)
{
- if (trp->file[file_dist].uid == trp->file[file_signature].uid
- && trp->file[file_dist].uid == trp->file[file_directive].uid)
- return true;
- else if (debug_level)
- logmsg (LOG_DEBUG, "%s: invalid triplet: UIDs differ", trp->name);
+ if (trp->file[file_dist].name == 0
+ && trp->file[file_signature].name == 0)
+ {
+ if (directive_get_value (trp, "filename", NULL))
+ return triplet_directive ;
+ }
+ else if (trp->file[file_dist].name
+ && trp->file[file_signature].name)
+ {
+ if (trp->file[file_dist].uid == trp->file[file_signature].uid
+ && trp->file[file_dist].uid == trp->file[file_directive].uid)
+ return triplet_complete;
+ else
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG, "%s: invalid triplet: UIDs differ",
+ trp->name);
+ return triplet_bad;
+ }
+ }
}
- else if (debug_level)
- logmsg (LOG_DEBUG, "%s: incomplete triplet", trp->name);
- return false;
+
+ return triplet_incomplete;
}
/* Unlink all parts of the triplet TRP */
@@ -157,17 +180,30 @@ triplet_processor (void *data, void *proc_data)
SP (trp->file[file_signature].name),
SP (trp->file[file_directive].name));
- if (valid_triplet_p (trp))
+ if (verify_directive_file (trp, dpair) == 0)
{
- if (debug_level)
- logmsg (LOG_DEBUG, "Processing triplet `%s'", trp->name);
- if (verify_triplet (trp, dpair) == 0)
- process_directives (trp, dpair);
- /* FIXME: if only directive file exists? */
- else
- remove_triplet (trp);
+ switch (check_triplet_state (trp))
+ {
+ case triplet_directive:
+ case triplet_complete:
+ if (debug_level)
+ logmsg (LOG_DEBUG, "Processing triplet `%s'", trp->name);
+ process_directives (trp, dpair);
+ return true;
+
+ case triplet_incomplete:
+ if (debug_level)
+ logmsg (LOG_DEBUG, "%s: incomplete triplet", trp->name);
+ /* ignore unless expired (see below); */
+ break;
+
+ case triplet_bad:
+ remove_triplet (trp);
+ return true;
+ }
}
- else if (triplet_expired_p (trp, dpair->file_sweep_time))
+
+ if (triplet_expired_p (trp, dpair->file_sweep_time))
remove_triplet (trp);
return true;
diff --git a/src/verify.c b/src/verify.c
index f64183a..7869618 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@ trim (char *str)
return len;
}
+/* Quote non-printable characters in INPUT. Point *OUTPUT to the malloc'ed
+ quoted string. Return its length. */
static size_t
quote_string (struct access_method *method, const char *input, char **poutput)
{
@@ -73,6 +75,10 @@ quote_string (struct access_method *method, const char *input, char **poutput)
return size;
}
+/* Expand PARAM by replacing %u with the quoted value of USER, %p with that
+ of PROJECT and %% with a single %. Return the malloc'ed result.
+ FIXME: Should we quote PARAM itself?
+*/
char *
expand_param (const char *param, const char *user, const char *project,
struct access_method *method)
@@ -157,7 +163,9 @@ expand_param (const char *param, const char *user, const char *project,
}
-
+
+/* Verify if USER has upload rights on the directory (project) requested
+ by TRP */
int
check_access_rights (struct file_triplet *trp, struct directory_pair *dpair,
const char *user)
@@ -216,15 +224,19 @@ check_access_rights (struct file_triplet *trp, struct directory_pair *dpair,
}
int
-verify_triplet (struct file_triplet *trp, struct directory_pair *dpair)
+verify_directive_file (struct file_triplet *trp, struct directory_pair *dpair)
{
- struct passwd *pw = getpwuid (TRIPLET_UID (trp));
+ struct passwd *pw;
char *user_name;
char *command;
struct access_method *method = &dpair->gpg_key_method;
const char *pubkey;
int rc;
+
+ if (!trp->file[file_directive].name)
+ return 1;
+ pw = getpwuid (TRIPLET_UID (trp));
if (!pw)
{
logmsg (LOG_ERR, "%s: getpwuid failed: %s",
@@ -258,6 +270,8 @@ verify_triplet (struct file_triplet *trp, struct directory_pair *dpair)
logmsg (LOG_ERR, "invalid signature for %s", trp->name);
return 1;
}
+ else if (debug_level)
+ logmsg (LOG_DEBUG, "%s: directive file signature OK", trp->name);
if (debug_level > 1)
{
@@ -269,16 +283,6 @@ verify_triplet (struct file_triplet *trp, struct directory_pair *dpair)
if (verify_directive_format (trp))
return 1;
- if (check_access_rights (trp, dpair, user_name))
- return 1;
-
- if (verify_detached_signature (trp, dpair))
- {
- logmsg (LOG_ERR, "invalid detached signature for %s", trp->name);
- return 1;
- }
-
- if (debug_level)
- logmsg (LOG_DEBUG, "%s: triplet verified successfully", trp->name);
return 0;
}
+
diff --git a/src/wydawca.c b/src/wydawca.c
index f514679..9918362 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
diff --git a/src/wydawca.h b/src/wydawca.h
index 918f6e0..cb42357 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -1,4 +1,4 @@
-/* wydawca - FTP release synchronisation daemon
+/* wydawca - FTP release synchronization daemon
Copyright (C) 2007 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
@@ -199,7 +199,8 @@ void method_copy_result (struct access_method *method, const char *res,
size_t size);
/* Verification functions */
-int verify_triplet (struct file_triplet *trp, struct directory_pair *dpair);
+int verify_directive_file (struct file_triplet *trp,
+ struct directory_pair *dpair);
int verify_directive_signature (struct file_triplet *trp,
struct directory_pair *dpair,
const char *pubkey);

Return to:

Send suggestions and report system problems to the System administrator.