summaryrefslogtreecommitdiff
path: root/builtin/receive-pack.c
AgeCommit message (Collapse)AuthorFilesLines
2015-08-03Merge branch 'jx/do-not-crash-receive-pack-wo-head'Libravatar Junio C Hamano1-1/+1
An attempt to delete a ref by pushing into a repositorywhose HEAD symbolic reference points at an unborn branch that cannot be created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD points at refs/heads/a) failed. * jx/do-not-crash-receive-pack-wo-head: receive-pack: crash when checking with non-exist HEAD
2015-07-22receive-pack: crash when checking with non-exist HEADLibravatar Jiang Xin1-1/+1
If HEAD of a repository points to a conflict reference, such as: * There exist a reference named 'refs/heads/jx/feature1', but HEAD points to 'refs/heads/jx', or * There exist a reference named 'refs/heads/feature', but HEAD points to 'refs/heads/feature/bad'. When we push to delete a reference for this repo, such as: git push /path/to/bad-head-repo.git :some/good/reference The git-receive-pack process will crash. This is because if HEAD points to a conflict reference, the function `resolve_refdup("HEAD", ...)` does not return a valid reference name, but a null buffer. Later matching the delete reference against the null buffer will cause git-receive-pack crash. Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23fsck: git receive-pack: support excluding objects from fsck'ingLibravatar Johannes Schindelin1-0/+11
The optional new config option `receive.fsck.skipList` specifies the path to a file listing the names, i.e. SHA-1s, one per line, of objects that are to be ignored by `git receive-pack` when `receive.fsckObjects = true`. This is extremely handy in case of legacy repositories where it would cause more pain to change incorrect objects than to live with them (e.g. a duplicate 'author' line in an early commit object). The intended use case is for server administrators to inspect objects that are reported by `git push` as being too problematic to enter the repository, and to add the objects' SHA-1 to a (preferably sorted) file when the objects are legitimate, i.e. when it is determined that those problematic objects should be allowed to enter the server. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23fsck (receive-pack): allow demoting errors to warningsLibravatar Johannes Schindelin1-2/+15
For example, missing emails in commit and tag objects can be demoted to mere warnings with git config receive.fsck.missingemail=warn The value is actually a comma-separated list. In case that the same key is listed in multiple receive.fsck.<msg-id> lines in the config, the latter configuration wins (this can happen for example when both $HOME/.gitconfig and .git/config contain message type settings). As git receive-pack does not actually perform the checks, it hands off the setting to index-pack or unpack-objects in the form of an optional argument to the --strict option. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-25show_ref_cb(): rewrite to take an object_id argumentLibravatar Michael Haggerty1-5/+3
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-25each_ref_fn: change to take an object_id parameterLibravatar Michael Haggerty1-1/+4
Change typedef each_ref_fn to take a "const struct object_id *oid" parameter instead of "const unsigned char *sha1". To aid this transition, implement an adapter that can be used to wrap old-style functions matching the old typedef, which is now called "each_ref_sha1_fn"), and make such functions callable via the new interface. This requires the old function and its cb_data to be wrapped in a "struct each_ref_fn_sha1_adapter", and that object to be used as the cb_data for an adapter function, each_ref_fn_adapter(). This is an enormous diff, but most of it consists of simple, mechanical changes to the sites that call any of the "for_each_ref" family of functions. Subsequent to this change, the call sites can be rewritten one by one to use the new interface. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-11Merge branch 'nd/multiple-work-trees'Libravatar Junio C Hamano1-1/+1
A replacement for contrib/workdir/git-new-workdir that does not rely on symbolic links and make sharing of objects and refs safer by making the borrowee and borrowers aware of each other. * nd/multiple-work-trees: (41 commits) prune --worktrees: fix expire vs worktree existence condition t1501: fix test with split index t2026: fix broken &&-chain t2026 needs procondition SANITY git-checkout.txt: a note about multiple checkout support for submodules checkout: add --ignore-other-wortrees checkout: pass whole struct to parse_branchname_arg instead of individual flags git-common-dir: make "modules/" per-working-directory directory checkout: do not fail if target is an empty directory t2025: add a test to make sure grafts is working from a linked checkout checkout: don't require a work tree when checking out into a new one git_path(): keep "info/sparse-checkout" per work-tree count-objects: report unused files in $GIT_DIR/worktrees/... gc: support prune --worktrees gc: factor out gc.pruneexpire parsing code gc: style change -- no SP before closing parenthesis checkout: clean up half-prepared directories in --to mode checkout: reject if the branch is already checked out elsewhere prune: strategies for linked checkouts checkout: support checking out into a new working directory ...
2015-04-14Merge branch 'jc/update-instead-into-void'Libravatar Junio C Hamano1-1/+20
A push into an unborn branch, with "receive.denyCurrentBranch" set to "updateInstead", did not check out the working tree as expected. * jc/update-instead-into-void: push-to-deploy: allow pushing into an unborn branch and updating it
2015-04-01push-to-deploy: allow pushing into an unborn branch and updating itLibravatar Junio C Hamano1-1/+20
Setting receive.denycurrentbranch to updateinstead and pushing into the current branch, when the working tree and the index is truly clean, is supposed to reset the working tree and the index to match the tree of the pushed commit. This did not work when pushing into an unborn branch. The code that drives push-to-checkout hook needs no change, as the interface is defined so that hook can decide what to do when the push is coming to an unborn branch and take an appropriate action since the beginning. Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-17ref_transaction_delete(): remove "have_old" parameterLibravatar Michael Haggerty1-2/+1
Instead, verify the reference's old value if and only if old_sha1 is non-NULL. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-17ref_transaction_update(): remove "have_old" parameterLibravatar Michael Haggerty1-1/+1
Instead, verify the reference's old value if and only if old_sha1 is non-NULL. ref_transaction_delete() will get the same treatment in a moment. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-11Merge branch 'jc/push-to-checkout'Libravatar Junio C Hamano1-25/+45
Extending the js/push-to-deploy topic, the behaviour of "git push" when updating the working tree and the index with an update to the branch that is checked out can be tweaked by push-to-checkout hook. * jc/push-to-checkout: receive-pack: support push-to-checkout hook receive-pack: refactor updateInstead codepath
2015-02-11Merge branch 'sb/atomic-push'Libravatar Junio C Hamano1-35/+130
"git push" has been taught a "--atomic" option that makes push to update more than one ref an "all-or-none" affair. * sb/atomic-push: Document receive.advertiseatomic t5543-atomic-push.sh: add basic tests for atomic pushes push.c: add an --atomic argument send-pack.c: add --atomic command line argument send-pack: rename ref_update_to_be_sent to check_to_send_update receive-pack.c: negotiate atomic push support receive-pack.c: add execute_commands_atomic function receive-pack.c: move transaction handling in a central place receive-pack.c: move iterating over all commands outside execute_commands receive-pack.c: die instead of error in case of possible future bug receive-pack.c: shorten the execute_commands loop over all commands
2015-01-08receive-pack: support push-to-checkout hookLibravatar Junio C Hamano1-1/+18
When receive.denyCurrentBranch is set to updateInstead, a push that tries to update the branch that is currently checked out is accepted only when the index and the working tree exactly matches the currently checked out commit, in which case the index and the working tree are updated to match the pushed commit. Otherwise the push is refused. This hook can be used to customize this "push-to-deploy" logic. The hook receives the commit with which the tip of the current branch is going to be updated, and can decide what kind of local changes are acceptable and how to update the index and the working tree to match the updated tip of the current branch. For example, the hook can simply run `git read-tree -u -m HEAD "$1"` in order to emulate 'git fetch' that is run in the reverse direction with `git push`, as the two-tree form of `read-tree -u -m` is essentially the same as `git checkout` that switches branches while keeping the local changes in the working tree that do not interfere with the difference between the branches. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: negotiate atomic push supportLibravatar Ronnie Sahlberg1-0/+11
This adds the atomic protocol option to allow receive-pack to inform the client that it has atomic push capability. This commit makes the functionality introduced in the previous commits go live for the serving side. The changes in documentation reflect the protocol capabilities of the server. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: add execute_commands_atomic functionLibravatar Stefan Beller1-1/+46
This introduces the new function execute_commands_atomic which will use one atomic transaction for all updates. The default behavior is still the old non atomic way, one ref at a time. This is to cause as little disruption as possible to existing clients. It is unknown if there are client scripts that depend on the old non-atomic behavior so we make it opt-in for now. A later patch will add the possibility to actually use the functionality added by this patch. For now use_atomic is always 0. Inspired-by: Ronnie Sahlberg <sahlberg@google.com> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: move transaction handling in a central placeLibravatar Stefan Beller1-14/+37
This moves all code related to transactions into the execute_commands_non_atomic function. This includes beginning and committing the transaction as well as dealing with the errors which may occur during the begin and commit phase of a transaction. No functional changes intended. Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: move iterating over all commands outside execute_commandsLibravatar Stefan Beller1-6/+13
This commit allows us in a later patch to easily distinguish between the non atomic way to update the received refs and the atomic way which is introduced in a later patch. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: die instead of error in case of possible future bugLibravatar Stefan Beller1-3/+1
Discussion on the previous patch revealed we rather want to err on the safe side. To do so we need to stop receive-pack in case of the possible future bug when connectivity is not checked on a shallow push. Also while touching that code we considered that removing the reported refs may be harmful in some situations. Sound the message more like a "This Cannot Happen, Please Investigate!" instead of giving advice to remove refs. Suggested-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07receive-pack.c: shorten the execute_commands loop over all commandsLibravatar Stefan Beller1-16/+27
Make the main "execute_commands" loop in receive-pack easier to read by splitting out some steps into helper functions. The new helper 'should_process_cmd' checks if a ref update is unnecessary, whether due to an error having occurred or for another reason. The helper 'warn_if_skipped_connectivity_check' warns if we have forgotten to run a connectivity check on a ref which is shallow for the client which would be a bug. This will help us to duplicate less code in a later patch when we make a second copy of the "execute_commands" loop. No functional change intended. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-12-22Merge branch 'js/push-to-deploy'Libravatar Junio C Hamano1-2/+91
"git push" into a repository with a working tree normally refuses to modify the branch that is checked out. The command learned to optionally do an equivalent of "git reset --hard" only when there is no change to the working tree and the index instead, which would be useful to "deploy" by pushing into a repository. * js/push-to-deploy: t5516: more tests for receive.denyCurrentBranch=updateInstead receive-pack: add another option for receive.denyCurrentBranch
2014-12-22Merge branch 'mh/simplify-repack-without-refs'Libravatar Junio C Hamano1-1/+1
"git remote update --prune" to drop many refs has been optimized. * mh/simplify-repack-without-refs: sort_string_list(): rename to string_list_sort() prune_remote(): iterate using for_each_string_list_item() prune_remote(): rename local variable repack_without_refs(): make the refnames argument a string_list prune_remote(): sort delete_refs_list references en masse prune_remote(): initialize both delete_refs lists in a single loop prune_remote(): exit early if there are no stale references
2014-12-05Merge branch 'rs/receive-pack-use-labs'Libravatar Junio C Hamano1-1/+1
* rs/receive-pack-use-labs: use labs() for variables of type long instead of abs()
2014-12-01receive-pack: refactor updateInstead codepathLibravatar Junio C Hamano1-25/+28
Keep the "there is nothing to update in a bare repository", "when the check and update process runs, here are the GIT_DIR and GIT_WORK_TREE" logic, which will be common regardless of how the decision to update and the actual update are done, in the original update_worktree() function, and split out the "working tree and the index must match the original HEAD exactly" and "use two-way read-tree to update the working tree" into a new push_to_deploy() helper function. This will allow customizing the logic more cleanly and easily. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-12-01path.c: make get_pathname() call sites return const char *Libravatar Nguyễn Thái Ngọc Duy1-1/+1
Before the previous commit, get_pathname returns an array of PATH_MAX length. Even if git_path() and similar functions does not use the whole array, git_path() caller can, in theory. After the commit, get_pathname() may return a buffer that has just enough room for the returned string and git_path() caller should never write beyond that. Make git_path(), mkpath() and git_path_submodule() return a const buffer to make sure callers do not write in it at all. This could have been part of the previous commit, but the "const" conversion is too much distraction from the core changes in path.c. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-30receive-pack: add another option for receive.denyCurrentBranchLibravatar Johannes Schindelin1-2/+91
When synchronizing between working directories, it can be handy to update the current branch via 'push' rather than 'pull', e.g. when pushing a fix from inside a VM, or when pushing a fix made on a user's machine (where the developer is not at liberty to install an ssh daemon let alone know the user's password). The common workaround – pushing into a temporary branch and then merging on the other machine – is no longer necessary with this patch. The new option is: 'updateInstead': Update the working tree accordingly, but refuse to do so if there are any uncommitted changes. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-25sort_string_list(): rename to string_list_sort()Libravatar Michael Haggerty1-1/+1
The new name is more consistent with the names of other string_list-related functions. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-17use labs() for variables of type long instead of abs()Libravatar René Scharfe1-1/+1
Using abs() on long values can cause truncation, so use labs() instead. Reported by Clang 3.5 (-Wabsolute-value, enabled by -Wall). Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-31Merge branch 'jc/push-cert'Libravatar Junio C Hamano1-2/+2
* jc/push-cert: receive-pack: avoid minor leak in case start_async() fails
2014-10-28receive-pack: avoid minor leak in case start_async() failsLibravatar René Scharfe1-2/+2
If the asynchronous start of copy_to_sideband() fails, then any env_array entries added to struct child_process proc by prepare_push_cert_sha1() are leaked. Call the latter function only after start_async() succeeded so that the allocated entries are cleaned up automatically by start_command() or finish_command(). Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-24Merge branch 'rs/run-command-env-array'Libravatar Junio C Hamano1-9/+14
Add managed "env" array to child_process to clarify the lifetime rules. * rs/run-command-env-array: use env_array member of struct child_process run-command: add env_array, an optional argv_array for env
2014-10-21Merge branch 'rs/ref-transaction'Libravatar Junio C Hamano1-4/+5
The API to update refs have been restructured to allow introducing a true transactional updates later. We would even allow storing refs in backends other than the traditional filesystem-based one. * rs/ref-transaction: (25 commits) ref_transaction_commit: bail out on failure to remove a ref lockfile: remove unable_to_lock_error refs.c: do not permit err == NULL remote rm/prune: print a message when writing packed-refs fails for-each-ref: skip and warn about broken ref names refs.c: allow listing and deleting badly named refs test: put tests for handling of bad ref names in one place packed-ref cache: forbid dot-components in refnames branch -d: simplify by using RESOLVE_REF_READING branch -d: avoid repeated symref resolution reflog test: test interaction with detached HEAD refs.c: change resolve_ref_unsafe reading argument to be a flags field refs.c: make write_ref_sha1 static fetch.c: change s_update_ref to use a ref transaction refs.c: ref_transaction_commit: distinguish name conflicts from other errors refs.c: pass a list of names to skip to is_refname_available refs.c: call lock_ref_sha1_basic directly from commit refs.c: refuse to lock badly named refs in lock_ref_sha1_basic rename_ref: don't ask read_ref_full where the ref came from refs.c: pass the ref log message to _create/delete/update instead of _commit ...
2014-10-20Merge branch 'rs/receive-pack-argv-leak-fix'Libravatar Junio C Hamano1-10/+8
* rs/receive-pack-argv-leak-fix: receive-pack: plug minor memory leak in unpack()
2014-10-19use env_array member of struct child_processLibravatar René Scharfe1-9/+14
Convert users of struct child_process to using the managed env_array for specifying environment variables instead of supplying an array on the stack or bringing their own argv_array. This shortens and simplifies the code and ensures automatically that the allocated memory is freed after use. Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-15refs.c: change resolve_ref_unsafe reading argument to be a flags fieldLibravatar Ronnie Sahlberg1-2/+2
resolve_ref_unsafe takes a boolean argument for reading (a nonexistent ref resolves successfully for writing but not for reading). Change this to be a flags field instead, and pass the new constant RESOLVE_REF_READING when we want this behaviour. While at it, swap two of the arguments in the function to put output arguments at the end. As a nice side effect, this ensures that we can catch callers that were unaware of the new API so they can be audited. Give the wrapper functions resolve_refdup and read_ref_full the same treatment for consistency. Signed-off-by: Ronnie Sahlberg <sahlberg@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-15refs.c: pass the ref log message to _create/delete/update instead of _commitLibravatar Ronnie Sahlberg1-2/+3
Change the ref transaction API so that we pass the reflog message to the create/delete/update functions instead of to ref_transaction_commit. This allows different reflog messages for each ref update in a multi-ref transaction. Signed-off-by: Ronnie Sahlberg <sahlberg@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-14Merge branch 'mh/lockfile'Libravatar Junio C Hamano1-0/+1
The lockfile API and its users have been cleaned up. * mh/lockfile: (38 commits) lockfile.h: extract new header file for the functions in lockfile.c hold_locked_index(): move from lockfile.c to read-cache.c hold_lock_file_for_append(): restore errno before returning get_locked_file_path(): new function lockfile.c: rename static functions lockfile: rename LOCK_NODEREF to LOCK_NO_DEREF commit_lock_file_to(): refactor a helper out of commit_lock_file() trim_last_path_component(): replace last_path_elm() resolve_symlink(): take a strbuf parameter resolve_symlink(): use a strbuf for internal scratch space lockfile: change lock_file::filename into a strbuf commit_lock_file(): use a strbuf to manage temporary space try_merge_strategy(): use a statically-allocated lock_file object try_merge_strategy(): remove redundant lock_file allocation struct lock_file: declare some fields volatile lockfile: avoid transitory invalid states git_config_set_multivar_in_file(): avoid call to rollback_lock_file() dump_marks(): remove a redundant call to rollback_lock_file() api-lockfile: document edge cases commit_lock_file(): rollback lock file on failure to rename ...
2014-10-13receive-pack: plug minor memory leak in unpack()Libravatar René Scharfe1-10/+8
The argv_array used in unpack() is never freed. Instead of adding explicit calls to argv_array_clear() use the args member of struct child_process and let run_command() and friends clean up for us. Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-10-08Merge branch 'jc/push-cert'Libravatar Junio C Hamano1-40/+353
Allow "git push" request to be signed, so that it can be verified and audited, using the GPG signature of the person who pushed, that the tips of branches at a public repository really point the commits the pusher wanted to, without having to "trust" the server. * jc/push-cert: (24 commits) receive-pack::hmac_sha1(): copy the entire SHA-1 hash out signed push: allow stale nonce in stateless mode signed push: teach smart-HTTP to pass "git push --signed" around signed push: fortify against replay attacks signed push: add "pushee" header to push certificate signed push: remove duplicated protocol info send-pack: send feature request on push-cert packet receive-pack: GPG-validate push certificates push: the beginning of "git push --signed" pack-protocol doc: typofix for PKT-LINE gpg-interface: move parse_signature() to where it should be gpg-interface: move parse_gpg_output() to where it should be send-pack: clarify that cmds_sent is a boolean send-pack: refactor inspecting and resetting status and sending commands send-pack: rename "new_refs" to "need_pack_data" receive-pack: factor out capability string generation send-pack: factor out capability string generation send-pack: always send capabilities send-pack: refactor decision to send update per ref send-pack: move REF_STATUS_REJECT_NODELETE logic a bit higher ...
2014-10-01lockfile.h: extract new header file for the functions in lockfile.cLibravatar Michael Haggerty1-0/+1
Move the interface declaration for the functions in lockfile.c from cache.h to a new file, lockfile.h. Add #includes where necessary (and remove some redundant includes of cache.h by files that already include builtin.h). Move the documentation of the lock_file state diagram from lockfile.c to the new header file. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-26Merge branch 'jc/ignore-sigpipe-while-running-hooks'Libravatar Junio C Hamano1-0/+6
pre- and post-receive hooks are no longer required to read all their inputs. * jc/ignore-sigpipe-while-running-hooks: receive-pack: allow hooks to ignore its standard input stream
2014-09-25receive-pack::hmac_sha1(): copy the entire SHA-1 hash outLibravatar Brian Gernhardt1-2/+2
clang gives the following warning: builtin/receive-pack.c:327:35: error: sizeof on array function parameter will return size of 'unsigned char *' instead of 'unsigned char [20]' [-Werror,-Wsizeof-array-argument] git_SHA1_Update(&ctx, out, sizeof(out)); ^ builtin/receive-pack.c:292:37: note: declared here static void hmac_sha1(unsigned char out[20], ^ Signed-off-by: Brian Gernhardt <brian@gernhardtsoftware.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-17signed push: allow stale nonce in stateless modeLibravatar Junio C Hamano1-10/+79
When operating with the stateless RPC mode, we will receive a nonce issued by another instance of us that advertised our capability and refs some time ago. Update the logic to check received nonce to detect this case, compute how much time has passed since the nonce was issued and report the status with a new environment variable GIT_PUSH_CERT_NONCE_SLOP to the hooks. GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The hooks are free to decide how large a slop it is willing to accept. Strictly speaking, the "nonce" is not really a "nonce" anymore in the stateless RPC mode, as it will happily take any "nonce" issued by it (which is protected by HMAC and its secret key) as long as it is fresh enough. The degree of this security degradation, relative to the native protocol, is about the same as the "we make sure that the 'git push' decided to update our refs with new objects based on the freshest observation of our refs by making sure the values they claim the original value of the refs they ask us to update exactly match the current state" security is loosened to accomodate the stateless RPC mode in the existing code without this series, so there is no need for those who are already using smart HTTP to push to their repositories to be alarmed any more than they already are. In addition, the server operator can set receive.certnonceslop configuration variable to specify how stale a nonce can be (in seconds). When this variable is set, and if the nonce received in the certificate that passes the HMAC check was less than that many seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS (instead of "SLOP") and the received nonce value is given in GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded hook to check if the certificate we received is recent enough. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-17signed push: fortify against replay attacksLibravatar Junio C Hamano1-8/+124
In order to prevent a valid push certificate for pushing into an repository from getting replayed in a different push operation, send a nonce string from the receive-pack process and have the signer include it in the push certificate. The receiving end uses an HMAC hash of the path to the repository it serves and the current time stamp, hashed with a secret seed (the secret seed does not have to be per-repository but can be defined in /etc/gitconfig) to generate the nonce, in order to ensure that a random third party cannot forge a nonce that looks like it originated from it. The original nonce is exported as GIT_PUSH_CERT_NONCE for the hooks to examine and match against the value on the "nonce" header in the certificate to notice a replay, but returned "nonce" header in the push certificate is examined by receive-pack and the result is exported as GIT_PUSH_CERT_NONCE_STATUS, whose value would be "OK" if the nonce recorded in the certificate matches what we expect, so that the hooks can more easily check. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-16receive-pack: allow hooks to ignore its standard input streamLibravatar Junio C Hamano1-0/+6
The pre-receive and post-receive hooks were designed to be an improvement over old style update and post-update hooks, which take the update information on their command line and are limited by the command line length limit. The same information is fed from the standard input to pre/post-receive hooks instead to lift this limitation. It has been mandatory for these new style hooks to consume the update information fully from the standard input stream. Otherwise, they would risk killing the receive-pack process via SIGPIPE. If a hook does not want to look at all the information, it is easy to send its standard input to /dev/null (perhaps a niche use of hook might need to know only the fact that a push was made, without having to know what objects have been pushed to update which refs), and this has already been done by existing hooks that are written carefully. However, because there is no good way to consistently fail hooks that do not consume the input fully (a small push may result in a short update record that may fit within the pipe buffer, to which the receive-pack process may manage to write before the hook has a chance to exit without reading anything, which will not result in a death-by-SIGPIPE of receive-pack), it can lead to a hard to diagnose "once in a blue moon" phantom failure. Lift this "hooks must consume their input fully" mandate. A mandate that is not enforced strictly is not helping us to catch mistakes in hooks. If a hook has a good reason to decide the outcome of its operation without reading the information we feed it, let it do so as it pleases. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-15signed push: remove duplicated protocol infoLibravatar Junio C Hamano1-0/+26
With the interim protocol, we used to send the update commands even though we already send a signed copy of the same information when push certificate is in use. Update the send-pack/receive-pack pair not to do so. The notable thing on the receive-pack side is that it makes sure that there is no command sent over the traditional protocol packet outside the push certificate. Otherwise a pusher can claim to be pushing one set of ref updates in the signed certificate while issuing commands to update unrelated refs, and such an update will evade later audits. Finally, start documenting the protocol. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-15receive-pack: GPG-validate push certificatesLibravatar Junio C Hamano1-0/+31
Reusing the GPG signature check helpers we already have, verify the signature in receive-pack and give the results to the hooks via GIT_PUSH_CERT_{SIGNER,KEY,STATUS} environment variables. Policy decisions, such as accepting or rejecting a good signature by a key that is not fully trusted, is left to the hook and kept outside of the core. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-15push: the beginning of "git push --signed"Libravatar Junio C Hamano1-0/+52
While signed tags and commits assert that the objects thusly signed came from you, who signed these objects, there is not a good way to assert that you wanted to have a particular object at the tip of a particular branch. My signing v2.0.1 tag only means I want to call the version v2.0.1, and it does not mean I want to push it out to my 'master' branch---it is likely that I only want it in 'maint', so the signature on the object alone is insufficient. The only assurance to you that 'maint' points at what I wanted to place there comes from your trust on the hosting site and my authentication with it, which cannot easily audited later. Introduce a mechanism that allows you to sign a "push certificate" (for the lack of better name) every time you push, asserting that what object you are pushing to update which ref that used to point at what other object. Think of it as a cryptographic protection for ref updates, similar to signed tags/commits but working on an orthogonal axis. The basic flow based on this mechanism goes like this: 1. You push out your work with "git push --signed". 2. The sending side learns where the remote refs are as usual, together with what protocol extension the receiving end supports. If the receiving end does not advertise the protocol extension "push-cert", an attempt to "git push --signed" fails. Otherwise, a text file, that looks like the following, is prepared in core: certificate version 0.1 pusher Junio C Hamano <gitster@pobox.com> 1315427886 -0700 7339ca65... 21580ecb... refs/heads/master 3793ac56... 12850bec... refs/heads/next The file begins with a few header lines, which may grow as we gain more experience. The 'pusher' header records the name of the signer (the value of user.signingkey configuration variable, falling back to GIT_COMMITTER_{NAME|EMAIL}) and the time of the certificate generation. After the header, a blank line follows, followed by a copy of the protocol message lines. Each line shows the old and the new object name at the tip of the ref this push tries to update, in the way identical to how the underlying "git push" protocol exchange tells the ref updates to the receiving end (by recording the "old" object name, the push certificate also protects against replaying). It is expected that new command packet types other than the old-new-refname kind will be included in push certificate in the same way as would appear in the plain vanilla command packets in unsigned pushes. The user then is asked to sign this push certificate using GPG, formatted in a way similar to how signed tag objects are signed, and the result is sent to the other side (i.e. receive-pack). In the protocol exchange, this step comes immediately before the sender tells what the result of the push should be, which in turn comes before it sends the pack data. 3. When the receiving end sees a push certificate, the certificate is written out as a blob. The pre-receive hook can learn about the certificate by checking GIT_PUSH_CERT environment variable, which, if present, tells the object name of this blob, and make the decision to allow or reject this push. Additionally, the post-receive hook can also look at the certificate, which may be a good place to log all the received certificates for later audits. Because a push certificate carry the same information as the usual command packets in the protocol exchange, we can omit the latter when a push certificate is in use and reduce the protocol overhead. This however is not included in this patch to make it easier to review (in other words, the series at this step should never be released without the remainder of the series, as it implements an interim protocol that will be incompatible with the final one). As such, the documentation update for the protocol is left out of this step. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-15receive-pack: factor out capability string generationLibravatar Junio C Hamano1-8/+14
Similar to the previous one for send-pack, make it easier and cleaner to add to capability advertisement. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-15receive-pack: factor out queueing of commandLibravatar Junio C Hamano1-21/+29
Make a helper function to accept a line of a protocol message and queue an update command out of the code from read_head_info(). Signed-off-by: Junio C Hamano <gitster@pobox.com>