/* wydawca - automatic release submission daemon Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff Wydawca 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. Wydawca 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 wydawca. If not, see . */ #include "wydawca.h" #include "sql.h" /* Return the length of the string without trailing whitespace */ size_t trim_length (const char *str) { size_t len; for (len = strlen (str); len > 0 && isspace (str[len-1]); len--) ; return len; } /* Chop off any trailing whitespace. Return the length of the resulting string. */ size_t trim (char *str) { size_t len = trim_length (str); str[len] = 0; return len; } #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 fill_project_name (struct file_triplet *trp) { 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; } 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)) { logmsg (LOG_ERR, _("%s: missing `directory' directive"), trp->file[file_directive].name); return 1; } p = strchr (directory, '/'); if (p) { size_t len = p - directory; if (len == 0) { logmsg (LOG_ERR, _("%s: empty `directory' directive"), trp->file[file_directive].name); return 1; } project = xmalloc (len + 1); memcpy (project, directory, len); project[len] = 0; } else project = xstrdup (directory); trp->project = xstrdup (project); return 0; } 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 verify_directive_file (struct file_triplet *trp, const struct spool *spool) { char *command; struct access_method *method = spool->access_method[project_uploader_method]; int rc; void *md; 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; md = method_open (method); if (!md) return 1; command = triplet_expand_method_query (method, md, trp); rc = method_run (method, md, command); free (command); if (rc) { logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name); method_close (method, md); return 1; } nrows = method_num_rows (method); if (nrows == 0) { logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name); method_close (method, md); return 1; } ncols = method_num_cols (method); if (ncols < 4) { logmsg (LOG_ERR, _("project-uploader method error: too few columns (%lu)"), (unsigned long) ncols); method_close (method, md); return 1; } head = tail = NULL; for (i = 0; i < nrows; i++) { 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); if (!head) { logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name); return 1; } trp->uploader_list = head; trp->uploader = NULL; if (verify_directive_signature (trp, spool)) { /*FIXME: Update stats */ logmsg (LOG_ERR, _("invalid signature for %s"), trp->name ? trp->name : "[unknown]"); return 1; } else if (debug_level) logmsg (LOG_DEBUG, _("%s: directive file signature OK"), trp->name); if (debug_level > 1) { int i; for (i = 0; trp->directive[i]; i++) logmsg (LOG_DEBUG, "directive[%d] = %s", i, trp->directive[i]); } if (verify_directive_format (trp)) return 1; return 0; }