diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-30 21:35:14 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-30 21:35:14 +0200 |
commit | a4b8dfab94b3ca44b6e3aecd7c0281ca2f5b51d5 (patch) | |
tree | 531d41fe7bb4adfba62024e6205cbfa742f7e70e /src | |
parent | 4c68f93c0c664e13a8572b43e33c138ce3bb8d28 (diff) | |
download | wydawca-a4b8dfab94b3ca44b6e3aecd7c0281ca2f5b51d5.tar.gz wydawca-a4b8dfab94b3ca44b6e3aecd7c0281ca2f5b51d5.tar.bz2 |
Do not require uploaders to be present in the system passwd database.
* src/wydawca.h (access_method_id): Remove verify_method,
gpg_key_method and user_data_method. Add project_uploader_method.
(uploader_info): New structure.
(struct file_triplet): Remove gid and user data fields.
Add uploader_count, uploader_list and uploader.
(TRIPLET_GID): Change definition.
(verify_directive_signature): Change signature.
(uploader_find_frp): New proto.
* src/verify.c (extract_plaintext): New function.
(fill_project_name): Rewrite. Parse directive file.
(uploader_find_frp): New function.
(check_access_rights): Remove.
(verify_directive_file): Rewrite.
* src/config.c (string_to_access_method_id): Reflect changes to the
access method system.
* src/builtin.c (default_ncol): Reflect changes to the
access method system.
* src/gpg.c (gpg_sig_ok_p): Remove.
(gpg_verify_signature): New function, based on
gpg_sig_ok_p.
(verify_directive_signature): Remove `pubkey' argument.
Register all public keys from the uploader list.
Do not call directive_parse, as the directive file must
already be parsed by the time the function is called.
* src/mail.c (get_uploader_email): New function.
(do_notify): Use get_uploader_email for notifying
users.
* src/triplet.c (hash_triplet_free): Reflect changes to
the triplet structure.
(format_file_data): Get user name from the system passwd database.
(fill_user_data): Remove.
(expand_user_real_name, expand_user_email): Reflect changes to
struct file_triplet.
* tests/etc/wydawca.rcin: Rewrite to reflect new access method
system.
* tests/mailstats.at, tests/notify-upl.at,
tests/upload-dry.at, tests/upload.at: Update.
Diffstat (limited to 'src')
-rw-r--r-- | src/builtin.c | 4 | ||||
-rw-r--r-- | src/config.c | 10 | ||||
-rw-r--r-- | src/gpg.c | 56 | ||||
-rw-r--r-- | src/mail.c | 33 | ||||
-rw-r--r-- | src/triplet.c | 88 | ||||
-rw-r--r-- | src/verify.c | 278 | ||||
-rw-r--r-- | src/wydawca.c | 1 | ||||
-rw-r--r-- | src/wydawca.h | 35 |
8 files changed, 311 insertions, 194 deletions
diff --git a/src/builtin.c b/src/builtin.c index d70a511..73b1d23 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -156,6 +156,4 @@ struct builtin_data_storage static int default_ncol[] = { - 1, /* verify-user: arbitrary return, usually user name */ - 1, /* gpg-key: key */ + 4, /* project-uploader: name, realname, email, pubkey */ 2, /* project-owner: email, realname */ - 2, /* user-data: email, realname */ }; diff --git a/src/config.c b/src/config.c index 8758802..4748a80 100644 --- a/src/config.c +++ b/src/config.c @@ -1041,6 +1041,4 @@ string_to_access_method_id (grecs_locus_t *locus, static const char *id_str[] = { - "verify-user", - "gpg-key", + "project-uploader", "project-owner", - "user-data", NULL @@ -1048,6 +1046,4 @@ string_to_access_method_id (grecs_locus_t *locus, static int id_num[] = { - verify_method, - gpg_key_method, - project_owner_method, - user_data_method + project_uploader_method, + project_owner_method }; @@ -151,3 +151,4 @@ wydawca_gpg_homedir () static int -gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) +gpg_verify_signature (gpgme_ctx_t ctx, gpgme_signature_t sig, + struct file_triplet *trp) { @@ -171,2 +172,11 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) logmsg (LOG_NOTICE, _("Good signature from %s"), uid); + trp->uploader = uploader_find_frp (trp->uploader_list, sig->fpr); + if (!trp->uploader) + { + logmsg (LOG_ERR, + _("good signature from %s, " + "but the uploader info for %s not found"), + uid, sig->fpr); + return 1; + } break; @@ -174,2 +184,3 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) case GPG_ERR_BAD_SIGNATURE: + UPDATE_STATS (STAT_BAD_SIGNATURE); logmsg (LOG_ERR, _("BAD signature from %s"), uid); @@ -178,2 +189,3 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) case GPG_ERR_NO_PUBKEY: + UPDATE_STATS (STAT_ACCESS_VIOLATIONS); logmsg (LOG_ERR, _("No public key")); @@ -182,2 +194,3 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) case GPG_ERR_NO_DATA: + UPDATE_STATS (STAT_BAD_TRIPLETS); logmsg (LOG_ERR, _("No signature")); @@ -186,2 +199,3 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) case GPG_ERR_SIG_EXPIRED: + UPDATE_STATS (STAT_BAD_SIGNATURE); logmsg (LOG_ERR, _("Expired signature from %s"), uid); @@ -190,2 +204,3 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) case GPG_ERR_KEY_EXPIRED: + UPDATE_STATS (STAT_BAD_SIGNATURE); logmsg (LOG_ERR, _("Key expired (%s)"), uid); @@ -205,3 +220,3 @@ int verify_directive_signature (struct file_triplet *trp, - const struct spool *spool, const char *pubkey) + const struct spool *spool) { @@ -212,8 +227,24 @@ verify_directive_signature (struct file_triplet *trp, int rc; - + struct uploader_info *uptr; + wydawca_gpg_homedir (); fail_if_err (gpgme_new (&ctx)); - fail_if_err (gpgme_data_new_from_mem (&key_data, pubkey, strlen (pubkey), - 0)); - fail_if_err (gpgme_op_import (ctx, key_data)); + + for (uptr = trp->uploader_list; uptr; uptr = uptr->next) + { + gpgme_import_result_t res; + gpgme_import_status_t pstat; + + fail_if_err (gpgme_data_new_from_mem (&key_data, + uptr->gpg_key, + strlen (uptr->gpg_key), + 0)); + fail_if_err (gpgme_op_import (ctx, key_data)); + res = gpgme_op_import_result (ctx); + pstat = res->imports; + uptr->fpr = xstrdup (pstat->fpr); + if (debug_level > 2) + logmsg (LOG_DEBUG, _("imported key: user = %s, fingerprint = %s"), + uptr->name, uptr->fpr); + } @@ -227,13 +258,4 @@ verify_directive_signature (struct file_triplet *trp, - 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); - result = gpgme_op_verify_result (ctx); - if (!gpg_sig_ok_p (ctx, result->signatures)) + if (!gpg_verify_signature (ctx, result->signatures, trp)) { @@ -243,2 +265,4 @@ verify_directive_signature (struct file_triplet *trp, } + else + rc = 0; } @@ -262,4 +262,29 @@ mail_stats () mu_address_t +get_uploader_email (struct uploader_info *info, struct file_triplet *trp, + const char **errp) +{ + mu_address_t addr; + mu_address_t rcpt = NULL; + int rc; + + rc = mu_address_create (&addr, info->email); + if (rc) + { + *errp = mu_strerror (rc); + return NULL; + } + + mu_address_set_personal (addr, 1, info->realname); + + /* This hack makes sure that mu_address_to_string (rcpt) will + return full email address (with personal part) */ + mu_address_union (&rcpt, addr); + mu_address_destroy (&addr); + + return rcpt; +} + +mu_address_t get_recipient (struct access_method *method, struct file_triplet *trp, - char **errp) + const char **errp) { @@ -329,3 +354,3 @@ do_notify (struct file_triplet *trp, enum notification_event ev, mu_address_t rcpt = NULL; - char *errp; + const char *errp; switch (ntf->tgt) @@ -337,4 +362,3 @@ do_notify (struct file_triplet *trp, enum notification_event ev, case notify_user: - rcpt = get_recipient (trp->spool->access_method[user_data_method], - trp, &errp); + rcpt = get_uploader_email (trp->uploader, trp, &errp); break; @@ -389,3 +413,2 @@ notify (struct notification *notification_list, - fill_project_name (trp); for (p = notification_list; p; p = p->next) diff --git a/src/triplet.c b/src/triplet.c index 0ddf997..048cdcb 100644 --- a/src/triplet.c +++ b/src/triplet.c @@ -54,11 +54,4 @@ hash_triplet_free (void *data) free (tp->tmp); - free (tp->user); - - if (tp->user_data) - { - for (i = 0; i < NITEMS (tp->user_data); i++) - free (tp->user_data[i]); - free (tp->user_data); - } - + /* FIXME: free uploader list */ + free (tp); @@ -324,2 +317,3 @@ format_file_data (struct file_triplet *trp, enum file_type type, char **pret) char timebuf[sizeof "YYYY-MM-DD HH:MM:SS +0000"]; + struct passwd *pw; struct group *grp; @@ -333,3 +327,3 @@ format_file_data (struct file_triplet *trp, enum file_type type, char **pret) char *buf; - + if (!info->name) @@ -346,8 +340,11 @@ format_file_data (struct file_triplet *trp, enum file_type type, char **pret) - user_name = trp->user; + pw = getpwuid (TRIPLET_UID (trp)); + if (!pw) + user_name = "unknown"; + else + user_name = pw->pw_name; - /* FIXME: group name should be stored in TRP after verification */ grp = getgrgid (TRIPLET_GID (trp)); if (!grp) - group_name = "UNKNOWN"; /* should not happen */ + group_name = "unknown"; /* should not happen */ else @@ -473,53 +470,6 @@ expand_user_name (struct metadef *def, void *data) struct file_triplet *trp = data; - return trp->user; -} - -static void -fill_user_data (struct file_triplet *trp) -{ - int rc; - struct access_method *method = trp->spool->access_method[user_data_method]; - char *text; - unsigned nrows, ncols; - struct passwd *pw; - void *md; - - if (trp->user_data) - return; - - if (method->type == method_none) - return; - - md = method_open (method); - if (!md) - return; - - pw = getpwuid (TRIPLET_UID (trp)); - if (!pw) - return; - text = triplet_expand_method_query (method, md, trp); - - rc = method_run (method, md, text); - free (text); - if (rc) - { - method_close (method, md); - return; - } - - nrows = method_num_rows (method); - ncols = method_num_cols (method); - - if (nrows > 0) - { - int i; - trp->user_data = xcalloc (ncols, sizeof (trp->user_data[0])); - for (i = 0; i < ncols; i++) - { - const char *str = method_result (method, md, 0, i); - if (str) - trp->user_data[i] = xstrdup (str); - } - } - method_close (method, md); + if (trp->uploader) + return trp->uploader->name; + def->value = "UNKNOWN"; + return def->value; } @@ -530,5 +480,4 @@ expand_user_real_name (struct metadef *def, void *data) struct file_triplet *trp = data; - fill_user_data (trp); - if (trp->user_data && trp->user_data[1]) - return trp->user_data[1]; + if (trp->uploader) + return trp->uploader->realname; def->value = "UNKNOWN"; @@ -541,5 +490,4 @@ expand_user_email (struct metadef *def, void *data) struct file_triplet *trp = data; - fill_user_data (trp); - if (trp->user_data && trp->user_data[0]) - return trp->user_data[0]; + if (trp->uploader) + return trp->uploader->email; def->value = "UNKNOWN"; diff --git a/src/verify.c b/src/verify.c index 15a2d8b..ed5f0cf 100644 --- a/src/verify.c +++ b/src/verify.c @@ -40,2 +40,51 @@ trim (char *str) +#define MSG_BEGIN_MARKER_STR "-----BEGIN PGP SIGNED MESSAGE-----\n" +#define MSG_BEGIN_MARKER_LEN (sizeof (MSG_BEGIN_MARKER_STR) - 1) + +#define SIG_BEGIN_MARKER_STR "-----BEGIN PGP SIGNATURE-----\n" +#define SIG_BEGIN_MARKER_LEN (sizeof (SIG_BEGIN_MARKER_STR) - 1) + +static int +extract_plaintext (char *blurb) +{ + char *start, *p; + + if (memcmp (blurb, MSG_BEGIN_MARKER_STR, MSG_BEGIN_MARKER_LEN)) + return 1; + + p = blurb + MSG_BEGIN_MARKER_LEN; + while (*p) + { + if (*p == '\n') + { + p++; + break; + } + + p = strchr (p, '\n'); + if (!p) + return 1; + p++; + } + + if (!*p) + return 1; + + start = p; + while (*p) + { + if (strncmp (p, SIG_BEGIN_MARKER_STR, SIG_BEGIN_MARKER_LEN) == 0) + { + *p++ = 0; + memmove (blurb, start, p - start); + return 0; + } + p = strchr (p, '\n'); + if (!p) + return 1; + p++; + } + return 1; +} + int @@ -43,8 +92,56 @@ fill_project_name (struct file_triplet *trp) { - char *project; - const char *directory; - char *p; + char *blurb; + size_t size; + FILE *fp; + char *project, *p; + const char *directory; + int rc; + + size = trp->file[file_directive].sb.st_size; + if (size <= MSG_BEGIN_MARKER_LEN) + { + logmsg (LOG_ERR, _("too small directive file %s"), + trp->file[file_directive].name); + return 1; + } + + fp = fopen (trp->file[file_directive].name, "r"); + if (!fp) + { + logmsg (LOG_ERR, _("cannot open file %s: %s"), + trp->file[file_directive].name, strerror (errno)); + return 1; + } - if (trp->project) - return 1; + blurb = xmalloc (size + 1); + + rc = fread (blurb, size, 1, fp); + fclose (fp); + + if (rc != 1) + { + logmsg (LOG_ERR, _("error reading file %s: %s"), + trp->file[file_directive].name, strerror (errno)); + free (blurb); + return 1; + } + + blurb[size] = 0; + if (extract_plaintext (blurb)) + { + logmsg (LOG_ERR, _("%s: unrecognized format"), + trp->file[file_directive].name); + free (blurb); + return 1; + } + + trp->blurb = blurb; + + if (directive_parse (trp)) + { + free (blurb); + trp->blurb = NULL; + return 1; + } + if (directive_get_value (trp, "directory", &directory)) @@ -71,3 +168,3 @@ fill_project_name (struct file_triplet *trp) project = xstrdup (directory); - trp->project = project; + trp->project = xstrdup (project); return 0; @@ -75,27 +172,41 @@ fill_project_name (struct file_triplet *trp) -/* Verify if USER has upload rights on the directory (project) requested - by TRP */ +struct uploader_info * +new_uploader_info (struct uploader_info *src) +{ + struct uploader_info *p = xmalloc (sizeof (*p)); + p->next = NULL; + p->name = src->name; + p->realname = src->realname; + p->gpg_key = src->gpg_key; + p->email = src->email; + p->fpr = NULL; + return p; +} + +struct uploader_info * +uploader_find_frp (struct uploader_info *list, const char *fpr) +{ + for (; list; list = list->next) + if (list->fpr && strcmp (list->fpr, fpr) == 0) + break; + return list; +} + int -check_access_rights (struct file_triplet *trp, const struct spool *spool, - const char *user) +verify_directive_file (struct file_triplet *trp, const struct spool *spool) { - struct access_method *method = spool->access_method[verify_method]; - int rc; char *command; - const char *result; + struct access_method *method = spool->access_method[project_uploader_method]; + int rc; void *md; - struct group *grp; + + size_t nrows, ncols, i; + struct uploader_info *head, *tail; + if (!trp->file[file_directive].name) + return 1; + if (fill_project_name (trp)) return 1; - grp = getgrnam (trp->project); - if (grp) - trp->gid = grp->gr_gid; - else - logmsg (LOG_NOTICE, _("no such group: %s"), trp->project); - if (debug_level) - logmsg (LOG_DEBUG, _("verifying access rights for user %s to project %s"), - user, trp->project); - md = method_open (method); @@ -108,7 +219,6 @@ check_access_rights (struct file_triplet *trp, const struct spool *spool, free (command); - method_close (method, md); if (rc) { - logmsg (LOG_ERR, _("cannot verify access rights for %s on %s"), - user, trp->project); + logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name); + method_close (method, md); return 1; @@ -116,9 +226,7 @@ check_access_rights (struct file_triplet *trp, const struct spool *spool, - result = method_result (method, md, 0, 0); - if (!result || strcmp (result, user)) + nrows = method_num_rows (method); + if (nrows == 0) { - UPDATE_STATS (STAT_ACCESS_VIOLATIONS); - logmsg (LOG_ERR, _("%s: %s has no rights on %s"), - trp->name, user, trp->project); - notify (spool->notification, trp, ev_bad_ownership); + logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name); + method_close (method, md); return 1; @@ -126,26 +234,8 @@ check_access_rights (struct file_triplet *trp, const struct spool *spool, - return 0; -} - -int -verify_directive_file (struct file_triplet *trp, const struct spool *spool) -{ - struct passwd *pw; - char *command; - struct access_method *method = spool->access_method[gpg_key_method]; - const char *pubkey; - int rc; - void *md; - - if (!trp->file[file_directive].name) - return 1; - - md = method_open (method); - if (!md) - return 1; - pw = getpwuid (TRIPLET_UID (trp)); - if (!pw) + ncols = method_num_cols (method); + if (ncols < 4) { - logmsg (LOG_ERR, _("%s: getpwuid failed: %s"), - trp->name, strerror (errno)); + logmsg (LOG_ERR, + _("project-uploader method error: too few columns (%lu)"), + (unsigned long) ncols); method_close (method, md); @@ -153,21 +243,56 @@ verify_directive_file (struct file_triplet *trp, const struct spool *spool) } - trp->gid = pw->pw_gid; - trp->user = xstrdup (pw->pw_name); - - command = triplet_expand_method_query (method, md, trp); - rc = method_run (method, md, command); - free (command); - if (rc) + head = tail = NULL; + for (i = 0; i < nrows; i++) { - logmsg (LOG_ERR, _("cannot get PGP key for %s"), trp->user); - method_close (method, md); - return 1; + const char *p; + struct uploader_info info, *ptr; + + memset (&info, 0, sizeof (info)); + p = method_result (method, md, i, 0); + if (p) + info.name = xstrdup (p); + p = method_result (method, md, i, 1); + if (p) + info.realname = xstrdup (p); + p = method_result (method, md, i, 2); + if (p) + info.email = xstrdup (p); + p = method_result (method, md, i, 3); + if (p) + info.gpg_key = xstrdup (p); + + if (debug_level > 3) + { + logmsg (LOG_DEBUG, _("name: %s"), SP (info.name)); + logmsg (LOG_DEBUG, _("realname: %s"), SP (info.realname)); + logmsg (LOG_DEBUG, _("gpg-key: %s"), SP (info.gpg_key)); + logmsg (LOG_DEBUG, _("email: %s"), SP (info.email)); + } + + if (!info.name || !info.realname || !info.gpg_key || !info.email) + { + logmsg (LOG_ERR, + _("project-uploader method error: malformed row %lu"), + (unsigned long) i); + free (info.name); + free (info.realname); + free (info.gpg_key); + free (info.email); + continue; + } + + ptr = new_uploader_info (&info); + if (tail) + tail->next = ptr; + else + head = ptr; + tail = ptr; } + + method_close (method, md); - pubkey = method_result (method, md, 0, 0); - if (!pubkey || pubkey[0] == 0) + if (!head) { - logmsg (LOG_ERR, _("no GPG key for %s"), trp->user); - method_close (method, md); + logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name); return 1; @@ -175,10 +300,10 @@ verify_directive_file (struct file_triplet *trp, const struct spool *spool) - if (debug_level > 3) - logmsg (LOG_DEBUG, _("public key: %s"), pubkey); + trp->uploader_list = head; + trp->uploader = NULL; - if (verify_directive_signature (trp, spool, pubkey)) + if (verify_directive_signature (trp, spool)) { /*FIXME: Update stats */ - logmsg (LOG_ERR, _("invalid signature for %s"), trp->name); - method_close (method, md); + logmsg (LOG_ERR, _("invalid signature for %s"), + trp->name ? trp->name : "[unknown]"); return 1; @@ -188,4 +313,2 @@ verify_directive_file (struct file_triplet *trp, const struct spool *spool) - method_close (method, md); - if (debug_level > 1) @@ -200,5 +323,2 @@ verify_directive_file (struct file_triplet *trp, const struct spool *spool) - if (check_access_rights (trp, spool, trp->user)) - return 1; - return 0; diff --git a/src/wydawca.c b/src/wydawca.c index 60cc628..07cac5c 100644 --- a/src/wydawca.c +++ b/src/wydawca.c @@ -240,3 +240,2 @@ grecs_print_diag (grecs_locus_t *locus, int err, int errcode, const char *msg) - static int uidc; diff --git a/src/wydawca.h b/src/wydawca.h index b390bff..15d803b 100644 --- a/src/wydawca.h +++ b/src/wydawca.h @@ -86,9 +86,6 @@ 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 */ + project_uploader_method, /* Retrieves names, gpg-keys, emails and + real names of the project uploaders */ + project_owner_method, /* Retrieves names and emails of the project + owners */ access_method_count @@ -163,2 +160,12 @@ struct file_info +struct uploader_info +{ + struct uploader_info *next; + char *name; + char *realname; + char *email; + char *gpg_key; + char *fpr; +}; + /* File triplet */ @@ -167,3 +174,2 @@ struct file_triplet char *name; /* Triplet base name */ - gid_t gid; /* Owner GID */ struct file_info file[FILE_TYPE_COUNT]; /* Components */ @@ -174,6 +180,8 @@ struct file_triplet size_t tmpsize; /* Size of memory allocated in tmp */ + /* 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) */ - char *user; /* User name (if known) */ - char **user_data; }; @@ -184,3 +192,3 @@ struct file_triplet /* GID is filled in after the triplet is finalized and verified */ -#define TRIPLET_GID(t) ((t)->gid) +#define TRIPLET_GID(t) ((t)->file[file_directive].sb.st_gid) @@ -411,4 +419,3 @@ int verify_directive_file (struct file_triplet *trp, int verify_directive_signature (struct file_triplet *trp, - const struct spool *spool, - const char *pubkey); + const struct spool *spool); int verify_detached_signature (struct file_triplet *trp, @@ -416,2 +423,4 @@ 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); |