diff --git a/src/ChangeLog b/src/ChangeLog index 2ccf2d5a3991077c965fa7d031ea48fc7551ef9e..ce2f3f372909ed12d972c8e63289b8b3669c906a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,23 @@ +2006-01-16 Derek Price <derek@ximbiot.com> + + * client.c (handle_openpgp_signatures): Rename to... + (handle_openpgp_signature): ...this and handle OpenPGP-signature + responses as documented. + (client_write_sigfile): Ditto on the response handling. + (responses): Rename OpenPGP-signatures to OpenPGP-signature. Handle + new function name. + * rcs.c (iRCS_get_openpgp_signatures): New function factored from... + (RCS_get_openpgp_signatures): ...here. Change API to return sigs + after base 64 decoding. + (RCS_has_openpgp_signatures): New function. + * rcs.h (RCS_get_openpgp_signatures): Update proto. + (RCS_has_openpgp_signatures): New proto. + * server.c (server_send_signatures): Handle raw signatures and match + response documentation. + (server_base_signatures): Use RCS_has_openpgp_signatures. + * verify.c (verify_fileproc): Handle raw signatures. + * vers_ts.c (Version_TS): Save RCSNode in input finfo. + 2006-01-14 Derek Price <derek@ximbiot.com> * cvs.h [CVS_VERIFY_CHECKOUTS_ENV, CVS_SIGN_COMMITS_ENV]: New macros. diff --git a/src/client.c b/src/client.c index 00ac3e7a74c01f02db20ecafccf809f312f6ef2b..ed497a38ebe46261b8207dcb379b811ca54c74c8 100644 --- a/src/client.c +++ b/src/client.c @@ -24,7 +24,6 @@ #include "client.h" /* GNULIB headers. */ -#include "base64.h" #include "getline.h" #include "save-cwd.h" @@ -33,6 +32,7 @@ #include "buffer.h" #include "difflib.h" #include "edit.h" +#include "gpg.h" #include "ignore.h" #include "recurse.h" #include "repos.h" @@ -2202,24 +2202,23 @@ handle_rcs_diff (char *args, size_t len) /* - * The OpenPGP-signatures response gives the signature for the file to be + * The OpenPGP-signature response gives the signature for the file to be * transmitted in the next Base-checkout or Temp-checkout response. */ -static char *stored_signatures; -static size_t stored_signatures_len; +static struct buffer *stored_signatures; static void -handle_openpgp_signatures (char *args, size_t len) +handle_openpgp_signature (char *args, size_t len) { - if (stored_signatures) - error (1, 0, "OpenPGP-signatures received before last one was used"); - - if (!base64_decode_alloc (args, len, &stored_signatures, - &stored_signatures_len)) - error (1, 0, - "Bad signature received from server (base64 decode failed)."); + int status; if (!stored_signatures) - error (1, errno, "Failed to allocate memory"); + stored_signatures = buf_nonio_initialize (NULL); + + status = next_signature (global_from_server, stored_signatures); + if (status == -2) + xalloc_die (); + else if (status) + error (1, 0, "Malformed signature received from server."); } @@ -2228,6 +2227,7 @@ static void client_write_sigfile (const char *sigfile, bool writable) { FILE *e; + size_t want; if (!stored_signatures) return; @@ -2235,16 +2235,28 @@ client_write_sigfile (const char *sigfile, bool writable) if (!writable && isfile (sigfile)) xchmod (sigfile, true); e = xfopen (sigfile, FOPEN_BINARY_WRITE); - if (fwrite (stored_signatures, sizeof *stored_signatures, - stored_signatures_len, e) != stored_signatures_len) - error (1, errno, "cannot write signature file `%s'", sigfile); + + want = buf_length (stored_signatures); + while (want > 0) + { + char *data; + size_t got; + + buf_read_data (stored_signatures, want, &data, &got); + + if (fwrite (data, sizeof *data, got, e) != got) + error (1, errno, "cannot write signature file `%s'", sigfile); + + want -= got; + } + if (fclose (e) == EOF) error (0, errno, "cannot close signature file `%s'", sigfile); if (!writable) xchmod (sigfile, false); - free (stored_signatures); + buf_free (stored_signatures); stored_signatures = NULL; } @@ -2448,6 +2460,9 @@ client_base_signatures (void *data_arg, List *ent_list, error (1, 0, "Server sent `Base-signatures' response without signature."); + if (stored_signatures && *clear) + error (1, 0, "Server sent unused signature data."); + /* Read REV from the server. */ read_line (&rev); @@ -3854,7 +3869,7 @@ struct response responses[] = rs_optional), RSP_LINE("Base-clear-signatures", handle_base_clear_signatures, response_type_normal, rs_optional), - RSP_LINE("OpenPGP-signatures", handle_openpgp_signatures, + RSP_LINE("OpenPGP-signature", handle_openpgp_signature, response_type_normal, rs_optional), /* Possibly should be response_type_error. */ @@ -4790,7 +4805,7 @@ start_server (void) continue; if (suppress_bases && !strncmp (rs->name, "Base-", 5)) continue; - if (suppress_bases && !strcmp (rs->name, "OpenPGP-signatures")) + if (suppress_bases && !strcmp (rs->name, "OpenPGP-signature")) continue; if (suppress_bases && !strcmp (rs->name, "Temp-checkout")) continue; diff --git a/src/rcs.c b/src/rcs.c index a24ae379c33b12dbc0069dfd421e0d40ae59625b..9062702ca7958ba0f8d2c6930a04e36c820800f2 100644 --- a/src/rcs.c +++ b/src/rcs.c @@ -4773,8 +4773,8 @@ workfile); -const char * -RCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, size_t *len) +static const char * +iRCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, size_t *len) { RCSVers *vers; Node *n; @@ -4784,7 +4784,8 @@ RCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, size_t *len) n = findnode (rcs->versions, rev); if (!n) - error (1, 0, "internal error: no revision information for %s", rev); + error (1, 0, "internal error: no revision information for r%s of %s", + rev, rcs->print_path); vers = n->data; n = findnode (vers->other_delta, "openpgp-signatures"); @@ -4798,6 +4799,50 @@ RCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, size_t *len) +/* Returns false on error. It is not an error if the requested revision has + * no OpenPGP signatures, but *OUT will be set to NULL. + */ +bool +RCS_get_openpgp_signatures (struct file_info *finfo, const char *rev, + char **out, size_t *len) +{ + const char *b64sig; + size_t b64len; + + b64sig = iRCS_get_openpgp_signatures (finfo->rcs, rev, &b64len); + + if (!b64sig) + { + *out = NULL; + *len = 0; + return true; + } + + if (!base64_decode_alloc (b64sig, b64len, out, len)) + { + error (0, 0, "Failed to decode base64 signature for `%s'", + finfo->fullname); + return false; + } + else if (!*out) + xalloc_die (); + + return true; +} + + + +/* Return true if the specified revision has any OpenPGP signature data + * attached. + */ +bool +RCS_has_openpgp_signatures (struct file_info *finfo, const char *rev) +{ + return iRCS_get_openpgp_signatures (finfo->rcs, rev, NULL); +} + + + void RCS_add_openpgp_signature (struct file_info *finfo, const char *rev) { diff --git a/src/rcs.h b/src/rcs.h index cba1964141cdf70106bdb0e05f810c08cc2dd8e9..c597d04cc7994866326a82138bce2672c0ca4a46 100644 --- a/src/rcs.h +++ b/src/rcs.h @@ -275,8 +275,9 @@ char *RCS_getexpand (RCSNode *); void RCS_setexpand (RCSNode *, const char *); int RCS_checkout (RCSNode *, const char *, const char *, const char *, const char *, const char *, RCSCHECKOUTPROC, void *); -const char *RCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, - size_t *len); +bool RCS_get_openpgp_signatures (struct file_info *finfo, const char *rev, + char **out, size_t *len); +bool RCS_has_openpgp_signatures (struct file_info *finfo, const char *rev); void RCS_add_openpgp_signature (struct file_info *finfo, const char *rev); int RCS_delete_openpgp_signatures (struct file_info *finfo, const char *rev, uint32_t keyid); diff --git a/src/sanity.sh b/src/sanity.sh index 327078c64441f90ff6744e8db620c5d2ca8b0639..8e1c3ae391759bc719f2f7cd0bc9cbfdf2ec3008 100755 --- a/src/sanity.sh +++ b/src/sanity.sh @@ -32361,7 +32361,7 @@ PrimaryServer=$PRIMARY_CVSROOT" mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME dotest writeproxy-noredirect-5 "$CVS_SERVER server" \ -"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version +"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents sign status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version ok ok ok @@ -32393,7 +32393,7 @@ EOF cd firstdir echo now you see me >file1 dotest writeproxy-noredirect-6 "$CVS_SERVER server" \ -"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version +"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents sign status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version ok ok ok @@ -32423,7 +32423,7 @@ EOF echo /file1/0/dummy+timestamp// >>CVS/Entries dotest writeproxy-noredirect-7 "$CVS_SERVER server" \ -"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version +"Valid-requests Root Valid-responses valid-requests Command-prep Referrer Repository Directory Relative-directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Signature Is-modified UseUnchanged Unchanged Notify Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log rlog list rlist global-list-quiet ls add remove update-patches gzip-file-contents sign status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors edit init annotate rannotate noop version ok ok Mode u=rw,g=rw,o=r diff --git a/src/server.c b/src/server.c index 7b09fa0c313c0e27c846acf5e77cedf5f603c4b5..aaa025df32f2c118dad26d9e2ca990c1235c72e1 100644 --- a/src/server.c +++ b/src/server.c @@ -8214,20 +8214,46 @@ cvs_output_tagged (const char *tag, const char *text) static void -server_send_signatures (RCSNode *rcs, const char *rev) +server_send_signatures (struct file_info *finfo, const char *rev) { - const char *signatures; - size_t siglen; + char *sig; + size_t len; + int status; + struct buffer *inbuf, *outbuf; - if (!supported_response ("OpenPGP-signatures")) + if (!supported_response ("OpenPGP-signature")) return; - if (!(signatures = RCS_get_openpgp_signatures (rcs, rev, &siglen))) + if (!RCS_get_openpgp_signatures (finfo, rev, &sig, &len)) + error (1, 0, + "Corrupt signature in r%s of `%s' (base64 decode failed).", + rev, finfo->fullname); + + if (!sig) + /* No signature data available. */ return; - buf_output0 (protocol, "OpenPGP-signatures "); - buf_output (protocol, signatures, siglen); - buf_output (protocol, "\n", 1); + /* Copy the sig into an input buffer. */ + inbuf = buf_nonio_initialize (NULL); + buf_output (inbuf, sig, len); + free (sig); + + /* Create an output buffer. */ + outbuf = buf_nonio_initialize (NULL); + + /* Read each signature, copying them to the net. */ + do + { + status = next_signature (inbuf, outbuf); + if (!status) + { + buf_output0 (protocol, "OpenPGP-signature\n"); + buf_append_buffer (protocol, outbuf); + } else if (status == -2) + xalloc_die (); + /* else status == EOF */ + } while (!status); + buf_send_counted (protocol); } @@ -8277,7 +8303,7 @@ iserver_base_checkout (RCSNode *rcs, struct file_info *finfo, const char *prev, */ return; - server_send_signatures (rcs, rev); + server_send_signatures (finfo, rev); /* FIXME: It would be more efficient if diffs could be sent when the * revision numbers haven't changed but the keywords have. @@ -8450,10 +8476,11 @@ server_base_signatures (struct file_info *finfo, const char *rev) || !supported_response ("Base-clear-signatures")) return; - server_send_signatures (finfo->rcs, rev); - - if (RCS_get_openpgp_signatures (finfo->rcs, rev, NULL)) + if (RCS_has_openpgp_signatures (finfo, rev)) + { + server_send_signatures (finfo, rev); buf_output0 (protocol, "Base-signatures "); + } else buf_output0 (protocol, "Base-clear-signatures "); diff --git a/src/verify.c b/src/verify.c index 7e77067ffe475a8b1ba55086ce4d1aab917df3fa..a504d2bafda1272f91df86f9652ec85c8690c533 100644 --- a/src/verify.c +++ b/src/verify.c @@ -30,7 +30,6 @@ #include <string.h> /* GNULIB headers. */ -#include "base64.h" #include "error.h" #include "xalloc.h" @@ -553,25 +552,15 @@ verify_fileproc (void *callerdat, struct file_info *finfo) else { /* In local mode, the signature data is still in the archive. */ - - const char *b64sig; - size_t b64len; - assert (finfo->rcs); - if ((b64sig = RCS_get_openpgp_signatures (finfo->rcs, e->version, - &b64len))) + if (!RCS_get_openpgp_signatures (finfo, e->version, &sigdata, + &siglen)) { - if (!base64_decode_alloc (b64sig, b64len, &sigdata, &siglen)) - { - error (0, 0, "Failed to decode base64 signature for `%s'", - finfo->fullname); - errors = true; - } - else if (!b64sig) - xalloc_die (); - /* else, got usable signature data in SIGDATA... fall out. */ + error (0, 0, "Failed to decode base64 signature for `%s'", + finfo->fullname); + errors = true; } - else + else if (!sigdata) { error (0, 0, "No signature available for `%s'", finfo->fullname); diff --git a/src/vers_ts.c b/src/vers_ts.c index b9ebccee6ce4d98664982bbd557b885049d8c93c..02f5103f043dbc01ff8baf845f3fe5cf739dc7ad 100644 --- a/src/vers_ts.c +++ b/src/vers_ts.c @@ -34,6 +34,10 @@ static void time_stamp_server (const char *, Vers_TS *, Entnode *); * set_time If set, set the last modification time of the user file * specified by FINFO to the checkin time of RET->vn_rcs. * + * OUTPUTS + * finfo FINFO->RCS will be updated if it was empty and RCS data + * is found and parsed. + * * RETURNS * Vers_TS structure for FINFO. */ @@ -195,6 +199,11 @@ Version_TS (struct file_info *finfo, const char *options, const char *tag, { /* squirrel away the rcsdata pointer for others */ vers_ts->srcfile = rcsdata; + if (!finfo->rcs) + { + rcsdata->refcount++; + finfo->rcs = rcsdata; + } if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0) {