Merge remote branch 'origin/pu'
This commit is contained in:
commit
90fed77927
|
@ -70,6 +70,8 @@ detail [here][gsdiff].
|
||||||
* simpler, yet far more powerful, config file syntax, including specifying
|
* simpler, yet far more powerful, config file syntax, including specifying
|
||||||
gitweb/daemon access. You'll need this power if you manage lots of
|
gitweb/daemon access. You'll need this power if you manage lots of
|
||||||
users+repos+combinations of access
|
users+repos+combinations of access
|
||||||
|
* apart from branch-name based restrictions, you can also restrict by
|
||||||
|
file/dir name changed (i.e., output of `git diff --name-only`)
|
||||||
* config file syntax gets checked upfront, and much more thoroughly
|
* config file syntax gets checked upfront, and much more thoroughly
|
||||||
* if your requirements are still too complex, you can split up the config
|
* if your requirements are still too complex, you can split up the config
|
||||||
file and delegate authority over parts of it
|
file and delegate authority over parts of it
|
||||||
|
|
|
@ -165,6 +165,40 @@ repo git
|
||||||
# looking for (`W` or `+`), or a minus (`-`), results in success, or failure,
|
# looking for (`W` or `+`), or a minus (`-`), results in success, or failure,
|
||||||
# respectively. A fallthrough also results in failure
|
# respectively. A fallthrough also results in failure
|
||||||
|
|
||||||
|
# FILE/DIR NAME BASED RESTRICTIONS
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
# Here's a hopefully self-explanatory example. Assume the project has the
|
||||||
|
# following contents at the top level: a README, a "doc/" directory, and an
|
||||||
|
# "src/" directory.
|
||||||
|
|
||||||
|
repo foo
|
||||||
|
RW+ = lead_dev # rule 1
|
||||||
|
RW = dev1 dev2 dev3 dev4 # rule 2
|
||||||
|
|
||||||
|
RW NAME/ = lead_dev # rule 3
|
||||||
|
RW NAME/doc/ = dev1 dev2 # rule 4
|
||||||
|
RW NAME/src/ = dev1 dev2 dev3 dev4 # rule 5
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
# - the "NAME/" is part of the syntax; think of it as a keyword if you like
|
||||||
|
|
||||||
|
# - file/dir NAME-based restrictions are *in addition* to normal (branch-name
|
||||||
|
# based) restrictions; they are not a *replacement* for them. This is why
|
||||||
|
# rule #2 (or something like it, maybe with a more specific branch-name) is
|
||||||
|
# needed; without it, dev1/2/3/4 cannot push any branches.
|
||||||
|
|
||||||
|
# - if a repo has *any* NAME/ rules, then NAME-based restrictions are checked
|
||||||
|
# for *all* users. This is why rule 3 is needed, even though we don't
|
||||||
|
# actually have any NAME-based restrictions on lead_dev. Notice the pattern
|
||||||
|
# on rule 3.
|
||||||
|
|
||||||
|
# - *each* file touched by the commits being pushed is checked against those
|
||||||
|
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
||||||
|
# changes to files in "doc/" and "src/" (but not the top level README), and
|
||||||
|
# dev3/4 can only push changes to files in "src/".
|
||||||
|
|
||||||
# GITWEB AND DAEMON STUFF
|
# GITWEB AND DAEMON STUFF
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
|
||||||
|
@ -213,18 +247,15 @@ repo gitolite
|
||||||
# examples above) or "git config --unset-all section.key" (for the last
|
# examples above) or "git config --unset-all section.key" (for the last
|
||||||
# example). Other forms (--add, the value_regex, etc) are not supported.
|
# example). Other forms (--add, the value_regex, etc) are not supported.
|
||||||
|
|
||||||
# SHELL ACCESS
|
# INCLUDE SOME OTHER FILE
|
||||||
# ------------
|
# -----------------------
|
||||||
|
|
||||||
# It is possible to give certain users shell access as well as allow them to
|
include "foo.conf"
|
||||||
# use gitolite features for their git repo access. The idea is to eliminate
|
|
||||||
# the need for 2 keys when both shell and gitolite access are needed.
|
|
||||||
|
|
||||||
# To give a user shell access, add the username to the special @SHELL group:
|
# this includes the contents of $GL_ADMINDIR/conf/foo.conf here
|
||||||
|
|
||||||
@SHELL = sitaram
|
# Notes:
|
||||||
|
# - the include statement is not allowed inside delegated fragments for
|
||||||
# Do not add people to this group indiscriminately. AUDITABILITY OF ACCESS
|
# security reasons.
|
||||||
# CONTROL CHANGES (AND OF REPO ACCESSES) WILL BE COMPROMISED IF ADMINS CAN
|
# - you can also use an absolute path if you like, although in the interests
|
||||||
# FIDDLE WITH THE ACTUAL (PLAIN TEXT) LOG FILES THAT GITOLITE KEEPS, WHICH
|
# of cloning the admin-repo sanely you should avoid doing this!
|
||||||
# THEY CAN EASILY DO IF THEY HAVE A SHELL.
|
|
||||||
|
|
|
@ -93,6 +93,19 @@ $PERSONAL="";
|
||||||
$GIT_PATH="";
|
$GIT_PATH="";
|
||||||
# $GIT_PATH="/opt/bin/";
|
# $GIT_PATH="/opt/bin/";
|
||||||
|
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
|
# if you want to give shell access to any gitolite user(s), name them here.
|
||||||
|
# Please see doc/6-ssh-troubleshooting.mkd for details on how this works.
|
||||||
|
|
||||||
|
# Do not add people to this list indiscriminately. AUDITABILITY OF ACCESS
|
||||||
|
# CONTROL CHANGES (AND OF REPO ACCESSES) WILL BE COMPROMISED IF ADMINS CAN
|
||||||
|
# FIDDLE WITH THE ACTUAL (PLAIN TEXT) LOG FILES THAT GITOLITE KEEPS, WHICH
|
||||||
|
# THEY CAN EASILY DO IF THEY HAVE A SHELL.
|
||||||
|
|
||||||
|
# syntax: space separated list of gitolite usernames in *one* string variable.
|
||||||
|
# $SHELL_USERS = "alice bob";
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
# per perl rules, this should be the last line in such a file:
|
# per perl rules, this should be the last line in such a file:
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -13,7 +13,9 @@ In this document:
|
||||||
* differences from gitosis
|
* differences from gitosis
|
||||||
* simpler syntax
|
* simpler syntax
|
||||||
* two levels of access rights checking
|
* two levels of access rights checking
|
||||||
|
* file/dir NAME based restrictions
|
||||||
* error checking the config file
|
* error checking the config file
|
||||||
|
* including config lines from other files
|
||||||
* delegating parts of the config file
|
* delegating parts of the config file
|
||||||
* easier to specify gitweb "description" and gitweb/daemon access
|
* easier to specify gitweb "description" and gitweb/daemon access
|
||||||
* easier to link gitweb authorisation with gitolite
|
* easier to link gitweb authorisation with gitolite
|
||||||
|
@ -215,8 +217,8 @@ Note that at this point no git program has entered the picture, and we have no
|
||||||
way of knowing what **ref** (branch, tag, etc) he is trying to update, even if
|
way of knowing what **ref** (branch, tag, etc) he is trying to update, even if
|
||||||
it is a "write" operation.
|
it is a "write" operation.
|
||||||
|
|
||||||
For a "read" operation to pass this check, the username (or `@all`) must be
|
For a "read" operation to pass this check, the username (or `@all`) must have
|
||||||
mentioned on some line in the config for this repo.
|
read permission (i.e., R, RW, or RW+) on at least one branch of the repo.
|
||||||
|
|
||||||
For a "write" operation, there is an additional restriction: lines specifying
|
For a "write" operation, there is an additional restriction: lines specifying
|
||||||
only `R` (read access) don't count. *The user must have write access to
|
only `R` (read access) don't count. *The user must have write access to
|
||||||
|
@ -235,6 +237,15 @@ any of the refexes match, the push succeeds. If none of them match, it fails.
|
||||||
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
|
#### file/dir NAME based restrictions
|
||||||
|
|
||||||
|
In addition to branch-name based restrictions, gitolite also allows you to
|
||||||
|
restrict what files or directories can be involved in changes being pushed.
|
||||||
|
This basically uses `git diff --name-only` to obtain the list of files being
|
||||||
|
changed, treating each filename as a "ref" to be matched.
|
||||||
|
|
||||||
|
Please see `conf/example.conf` for syntax and examples.
|
||||||
|
|
||||||
#### error checking the config file
|
#### error checking the config file
|
||||||
|
|
||||||
gitosis does not do any. I just found out that if you mis-spell `members` as
|
gitosis does not do any. I just found out that if you mis-spell `members` as
|
||||||
|
@ -244,6 +255,10 @@ was denied.
|
||||||
Gitolite "compiles" the config file first and keyword typos *are* caught so
|
Gitolite "compiles" the config file first and keyword typos *are* caught so
|
||||||
you know right away.
|
you know right away.
|
||||||
|
|
||||||
|
#### including config lines from other files
|
||||||
|
|
||||||
|
See the entry under "INCLUDE SOME OTHER FILE" in `conf/example.conf`.
|
||||||
|
|
||||||
#### delegating parts of the config file
|
#### delegating parts of the config file
|
||||||
|
|
||||||
You can now split up the config file and delegate the authority to specify
|
You can now split up the config file and delegate the authority to specify
|
||||||
|
@ -461,7 +476,7 @@ etc. You'd just like a simple way to know what repos you have access to.
|
||||||
Easy! Just use ssh and try to log in as if you were attempting to get a
|
Easy! Just use ssh and try to log in as if you were attempting to get a
|
||||||
shell:
|
shell:
|
||||||
|
|
||||||
$ ssh gitolite
|
$ ssh gitolite info
|
||||||
PTY allocation request failed on channel 0
|
PTY allocation request failed on channel 0
|
||||||
hello sitaram, the gitolite version here is v0.6-17-g94ed189
|
hello sitaram, the gitolite version here is v0.6-17-g94ed189
|
||||||
you have the following permissions:
|
you have the following permissions:
|
||||||
|
@ -486,7 +501,9 @@ that code path to better use :-)
|
||||||
***IMPORTANT CAVEAT: if you use deny rules, the order of the rules also makes
|
***IMPORTANT CAVEAT: if you use deny rules, the order of the rules also makes
|
||||||
a difference, where earlier it did not. Please review your ruleset carefully
|
a difference, where earlier it did not. Please review your ruleset carefully
|
||||||
or test it. In particular, do not use `@all` in a deny rule -- it won't work
|
or test it. In particular, do not use `@all` in a deny rule -- it won't work
|
||||||
as you might expect***.
|
as you might expect***. Also, deny rules are only processed in the second
|
||||||
|
level checks (see "two levels of access rights checking" above), which means
|
||||||
|
they only apply to write operations.
|
||||||
|
|
||||||
Take a look at the following snippet, which *seems* to say that "bruce" can
|
Take a look at the following snippet, which *seems* to say that "bruce" can
|
||||||
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
|
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
|
||||||
|
|
|
@ -61,35 +61,37 @@ You do this by adding branches to the `gitolite-admin` repo:
|
||||||
|
|
||||||
# the admin repo access was probably like this to start with:
|
# the admin repo access was probably like this to start with:
|
||||||
repo gitolite-admin
|
repo gitolite-admin
|
||||||
RW+ = sitaram
|
RW+ = sitaram
|
||||||
# now add these lines to the config for the admin repo
|
# now add these lines to the config for the admin repo
|
||||||
RW webbrowser_repos = alice
|
RW = alice bob mallory
|
||||||
RW webserver_repos = bob
|
RW+ NAME/ = sitaram
|
||||||
RW malware_repos = mallory
|
RW NAME/conf/fragments/webbrowser_repos = alice
|
||||||
|
RW NAME/conf/fragments/webserver_repos = bob
|
||||||
|
RW NAME/conf/fragments/malware_repos = mallory
|
||||||
|
|
||||||
|
This uses gitolite's ability to restrict pushes by file/dir name being changed
|
||||||
|
-- the syntax you see above ensures that, while "sitaram" does not have any
|
||||||
|
NAME based restrictions, the other 3 users do. See `conf/example.conf` for
|
||||||
|
syntax and notes.
|
||||||
|
|
||||||
As you can see, **for each repo group** you want to delegate authority over,
|
As you can see, **for each repo group** you want to delegate authority over,
|
||||||
there's a **branch with the same name** in the `gitolite-admin` repo. If you
|
there's a rule for a **corresponding file** in `conf/fragments` in the
|
||||||
have write access to that branch, you are allowed to define rules for repos in
|
`gitolite-admin` repo. If you have write access to that file, you are allowed
|
||||||
that repo group.
|
to define rules for repos in that repo group.
|
||||||
|
|
||||||
In other words, we use gitolite's per-branch permissions to "enforce" the
|
In other words, we use gitolite's file/dir NAME-based permissions to "enforce"
|
||||||
separation between the delegated configs!
|
the separation between the delegated configs!
|
||||||
|
|
||||||
Here's how to use this in practice:
|
Here's how to use this in practice:
|
||||||
|
|
||||||
* Alice clones the `gitolite-admin` repo, creates (if not already created) and
|
* Alice clones the `gitolite-admin` repo, and adds a file called
|
||||||
checks out a new branch called `webbrowser_repos`, and adds a file called
|
`conf/fragments/webbrowser_repos.conf`
|
||||||
`conf/fragments/webbrowser_repos.conf` in that branch
|
|
||||||
|
|
||||||
* (the rest of the contents of that branch do not matter; she can keep
|
|
||||||
all the other files or delete all of them -- it doesn't make any
|
|
||||||
difference. Only that one specific file is used).
|
|
||||||
|
|
||||||
* she writes in this file any access control rules for the "firefox" and
|
* she writes in this file any access control rules for the "firefox" and
|
||||||
"lynx" repos. She should not write access rules for any other project --
|
"lynx" repos. She should not write access rules for any other project --
|
||||||
they will be ignored
|
they will be ignored
|
||||||
|
|
||||||
* Alice then commits and pushes this branch to the `gitolite-admin` repo
|
* Alice then commits and pushes to the `gitolite-admin` repo
|
||||||
|
|
||||||
Naturally, a successful push invokes the post-update hook that the admin repo
|
Naturally, a successful push invokes the post-update hook that the admin repo
|
||||||
has, which eventually runs the compile script. The **net effect** is as if
|
has, which eventually runs the compile script. The **net effect** is as if
|
||||||
|
|
|
@ -1,92 +1,188 @@
|
||||||
# ssh troubleshooting
|
# ssh troubleshooting
|
||||||
|
|
||||||
Update 2009-12-23: most of this document is now of historical interest and
|
|
||||||
will be totally revamped when I have time. For now, just note this amendment.
|
|
||||||
|
|
||||||
The document below says "we can't use the same key for both [gitolite access
|
|
||||||
and shell access]...". We've managed (thanks to an idea from Jesse Keating)
|
|
||||||
to get around this. Now it *is* possible for a single key to allow both
|
|
||||||
gitolite access *and* shell access.
|
|
||||||
|
|
||||||
This is done by placing such a user in a special `@SHELL` group in the
|
|
||||||
gitolite config file. As usual, please see `conf/example.conf` for more info
|
|
||||||
on this, since I'm using that as a central place to document anything
|
|
||||||
concerned with the conf file.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Ssh has always been the biggest troublespot in all this. While gitolite makes
|
|
||||||
it as easy as possible, you might still run into trouble sometimes.
|
|
||||||
|
|
||||||
In this document:
|
In this document:
|
||||||
|
|
||||||
* ssh sanity checks
|
* basic ssh troubleshooting
|
||||||
* explanation
|
* passphrases versus passwords
|
||||||
|
* ssh-agent problems
|
||||||
|
* basic ssh troubleshooting for the main admin
|
||||||
|
* basic ssh troubleshooting for a normal user
|
||||||
|
* details
|
||||||
* files on the server
|
* files on the server
|
||||||
* files on client
|
* files on client
|
||||||
* why two keys on client
|
* why two keys on client
|
||||||
* more complex ssh setups
|
* more complex ssh setups
|
||||||
* two gitolite servers to manage?
|
* two gitolite servers to manage?
|
||||||
* further reading
|
* giving shell access to gitolite users
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
> But before we get to all that, let's clarify that all this is applicable
|
This document should help you troubleshoot ssh-related problems in accessing
|
||||||
> **only** to the gitolite **admin**. He's the only one who needs both a
|
gitolite *after* the install has completed successfully.
|
||||||
> shell and gitolite access, so he has **two** pubkeys in play.
|
|
||||||
|
|
||||||
> Normal users have only one pubkey, since they are only allowed to access
|
In addition, I **strongly** recommend reading [this document][glb] -- it's a
|
||||||
> gitolite itself. They do not need to worry about any of this stuff, and
|
very detailed look at how gitolite uses ssh's features on the server side.
|
||||||
> their repo urls are very simple, like: `git@my.git.server:reponame.git`.
|
Most people don't know ssh as well as they *think* they do; even if you dont
|
||||||
|
have any problems right now, it's worth skimming over.
|
||||||
|
|
||||||
----
|
In addition to both these documents, there's now a program called
|
||||||
|
`sshkeys-lint` that you can run on your client. Run it without arguments to
|
||||||
|
get help on how to run it and what inputs it needs.
|
||||||
|
|
||||||
### ssh sanity checks
|
Please also note that ssh problems don't always look like ssh problems. One
|
||||||
|
common example: when the remote says the repo you're trying to access "does
|
||||||
|
not appear to be a git repository", and yet you are sure it exists, you
|
||||||
|
haven't mis-spelled it, etc. Another example is being able to access
|
||||||
|
repositories using the full unix path (typically like
|
||||||
|
`git@server:repositories/reponame.git`, assuming default `$REPO_BASE` setting,
|
||||||
|
instead of specifying only the part below `$REPO_BASE`, i.e.,
|
||||||
|
`git@server:reponame.git`).
|
||||||
|
|
||||||
There are two quick sanity checks you can run:
|
[Both these errors indicate that you managed to bypass gitolite completely and
|
||||||
|
are using your shell access -- instead of running via
|
||||||
|
`/some/path/gl-auth-command <your_username>` it is just going to bash and
|
||||||
|
working from there!]
|
||||||
|
|
||||||
* running `ssh gitolite` should get you a list of repos you have rights to
|
### basic ssh troubleshooting
|
||||||
access, as described [here][myrights]
|
|
||||||
|
[glb]: http://sitaramc.github.com/0-installing/9-gitolite-basics.html#IMPORTANT_overview_of_ssh
|
||||||
|
|
||||||
|
I assume the gitolite server is called "server" and the user hosting all the
|
||||||
|
gitolite repos is "git". I will also be using "sitaram" as the *gitolite
|
||||||
|
username* of the admin.
|
||||||
|
|
||||||
|
Unless specifically mentioned, all these commands are run on the user's or
|
||||||
|
admin's workstation, not on the server.
|
||||||
|
|
||||||
|
#### passphrases versus passwords
|
||||||
|
|
||||||
|
When you create an ssh keypair, you have the option of protecting it with a
|
||||||
|
passphrase. When you subsequently use that keypair to access a remote host,
|
||||||
|
your *local* ssh client needs to unlock the corresponding private key, and ssh
|
||||||
|
will probably ask for the passphrase you set when you created the keypair.
|
||||||
|
|
||||||
|
Do not confuse or mistake this prompt (`Enter passphrase for key
|
||||||
|
'/home/sitaram/.ssh/id_rsa':`) for a password prompt from the remote server!
|
||||||
|
|
||||||
|
You have two choices to avoid this prompt every time you try to access the
|
||||||
|
remote. The first is to create keypairs *without* a passphrase (just hit
|
||||||
|
enter when prompted for one). **Be sure to add a passphrase later, once
|
||||||
|
everything is working, using `ssh-keygen -p`**.
|
||||||
|
|
||||||
|
The second is to use `ssh-agent` (or `keychain`, which in turn uses
|
||||||
|
`ssh-agent`) or something like that to manage your keys. Other than the next
|
||||||
|
section, further discussion of this is out of scope of this document.
|
||||||
|
|
||||||
|
#### ssh-agent problems
|
||||||
|
|
||||||
|
1. Run `ssh-add -l`. If this responds with either "The agent has no
|
||||||
|
identities." or "Could not open a connection to your authentication
|
||||||
|
agent.", skip this section.
|
||||||
|
|
||||||
|
2. However, if it lists some keys, like this:
|
||||||
|
|
||||||
|
2048 fc:c1:48:1e:06:31:97:a4:8b:fc:37:b2:76:14:c7:53 /home/sitaram/.ssh/id_rsa (RSA)
|
||||||
|
2048 d2:e0:7f:fa:1a:89:22:41:bb:06:d9:ff:a7:27:36:5c /home/sitaram/.ssh/sitaram (RSA)
|
||||||
|
|
||||||
|
then run `ls ~/.ssh` and make sure that all the keypairs you have there
|
||||||
|
are represented in the `ssh-add -l` output.
|
||||||
|
|
||||||
|
3. If you find any keypairs in `~/.ssh` that are not represented in the
|
||||||
|
`ssh-add -l` output, add them. For instance, if `ssh-add -l` showed me
|
||||||
|
only the `id_rsa` key, but I also had a `sitaram` (and `sitaram.pub`)
|
||||||
|
keypair, I'd run `ssh-add ~/.ssh/sitaram` to add it.
|
||||||
|
|
||||||
|
This is because ssh-agent has a quirk: if `ssh-add -l` shows *any* keys at
|
||||||
|
all, ssh will only use those keys. Even if you explicitly specify an unlisted
|
||||||
|
key using `ssh -i` or an `identityfile` directive in the config file, it won't
|
||||||
|
use it.
|
||||||
|
|
||||||
|
#### basic ssh troubleshooting for the main admin
|
||||||
|
|
||||||
|
You're the "main admin" if you're trying to access gitolite from the same
|
||||||
|
workstation and user account where you ran the "easy install" command. You
|
||||||
|
should have two keypairs in your `~/.ssh` directory. The pair called `id_rsa`
|
||||||
|
(and `id_rsa.pub`) was probably the first one you created, and you used this
|
||||||
|
to get passwordless (pubkey based) access to the server (which was a
|
||||||
|
pre-requisite for running the easy install command).
|
||||||
|
|
||||||
|
The second keypair has the same name as the last argument in the easy install
|
||||||
|
command you ran (in my case, `sitaram` and `sitaram.pub`). It was probably
|
||||||
|
created by the easy install script, and is the key used for gitolite access.
|
||||||
|
|
||||||
|
In addition, you should have a "gitolite" paragraph in your `~/.ssh/config`,
|
||||||
|
looking something like this:
|
||||||
|
|
||||||
|
host gitolite
|
||||||
|
user git
|
||||||
|
hostname server
|
||||||
|
identityfile ~/.ssh/sitaram
|
||||||
|
|
||||||
|
If any of these are not true, you did something funky in your install; email
|
||||||
|
me or hop onto #git and hope for the best ;-)
|
||||||
|
|
||||||
|
Otherwise, run these checks:
|
||||||
|
|
||||||
|
1. `ssh git@server` should get you a command line.
|
||||||
|
|
||||||
|
If it asks you for a password, then your `id_rsa` keypair changed after
|
||||||
|
you ran the easy install, or someone fiddled with the
|
||||||
|
`~/.ssh/authorized_keys` file on the server.
|
||||||
|
|
||||||
|
If it prints [gitolite version and access info][myrights], you managed to
|
||||||
|
overwrite the `id_rsa` keypair with the `sitaram` keypair, or something
|
||||||
|
equally weird.
|
||||||
|
|
||||||
|
2. `ssh gitolite info` should print some [gitolite version and access
|
||||||
|
info][myrights]. If you get the output of the GNU info command instead,
|
||||||
|
you probably reused your `id_rsa` keypair as your `sitaram` keypair, or
|
||||||
|
overwrote the `sitaram` keypair with the `id_rsa` keypair.
|
||||||
|
|
||||||
|
There are many ways to fix this, depending on where and what the damage is.
|
||||||
|
The most generic way (and therefore time-taking) is to re-install gitolite
|
||||||
|
from scratch:
|
||||||
|
|
||||||
|
* make a backup of your gitolite-admin repo clone somewhere (basically your
|
||||||
|
"keydir/*.pub" and your "conf/gitolite.conf"). If necessary get these
|
||||||
|
files from the server's `~/.gitolite` directory.
|
||||||
|
* log on to the server somehow (using some other account, using a password,
|
||||||
|
su-ing in, etc) and delete `~/.ssh/authorized_keys`. Rename or move aside
|
||||||
|
`~/.gitolite` so that also looks like it is missing.
|
||||||
|
* back on your workstation, make sure you have 2 keypairs (`id_rsa` and
|
||||||
|
`sitaram`, along with corresponding `.pub` files). Create them if needed.
|
||||||
|
Also make sure they are *different* and not a copy of each other :-)
|
||||||
|
* install gitolite normally:
|
||||||
|
* run `ssh-copy-id -i ~/.ssh/id_rsa git@server` to get passwordless
|
||||||
|
access to the server. (Mac users may have to do this step manually)
|
||||||
|
* make sure `ssh git@server pwd` prints the `$HOME` of `git@server`
|
||||||
|
**without** asking for a password. Do not proceed till this works.
|
||||||
|
* run easy install again, (in my case: `cd gitolite-source;
|
||||||
|
src/gl-easy-install -q git server sitaram`)
|
||||||
|
* go to your gitolite-admin repo clone, and copy `conf/gitolite.conf` and
|
||||||
|
`keydir/*.pub` from your backup to this directory
|
||||||
|
* copy (be sure to overwrite!) `~/.ssh/sitaram.pub` also to keydir
|
||||||
|
* now `git add keydir; git commit; git push -f`
|
||||||
|
|
||||||
|
That's a long sequence but it should work.
|
||||||
|
|
||||||
|
#### basic ssh troubleshooting for a normal user
|
||||||
|
|
||||||
|
For a normal user, life is much simpler. They should have only one pubkey,
|
||||||
|
which was previously sent to the gitolite admin to add into the admin repo's
|
||||||
|
`keydir` as "user.pub", and then "user" given permissions to some repo.
|
||||||
|
|
||||||
|
`ssh git@server info` should get you [gitolite version and access
|
||||||
|
info][myrights]. If it asks you for a password, your pubkey was not sent to
|
||||||
|
the server properly. Check with your admin.
|
||||||
|
|
||||||
[myrights]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#myrights
|
[myrights]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#myrights
|
||||||
|
|
||||||
* conversely, `ssh git@server` should get you a command line
|
If it gets you the GNU info command output, you have shell access. This means
|
||||||
|
you had command line access to the server *before* you were added as a
|
||||||
|
gitolite user. If you send that same key to your gitolite admin to include in
|
||||||
|
the admin repo, it won't work. For reasons why, see below.
|
||||||
|
|
||||||
If one or both of these does not work as expected, do this:
|
### details
|
||||||
|
|
||||||
* first, check that your `~/.ssh` has two public keys, like below:
|
|
||||||
|
|
||||||
$ ls -al ~/.ssh/*.pub
|
|
||||||
-rw-r--r-- 1 sitaram sitaram 409 2008-04-21 17:42 /home/sitaram/.ssh/id_rsa.pub
|
|
||||||
-rw-r--r-- 1 sitaram sitaram 409 2009-10-15 16:25 /home/sitaram/.ssh/sitaram.pub
|
|
||||||
|
|
||||||
If it doesn't you have either lost your keys or you're on the wrong
|
|
||||||
machine. As long as you have password access to the server you can alweys
|
|
||||||
recover; just pretend you're installing from scratch and start over.
|
|
||||||
|
|
||||||
* next, try running `ssh-add -l`. On my desktop the output looks like this:
|
|
||||||
|
|
||||||
2048 63:ea:ab:10:d2:4f:88:f4:85:cb:d3:7d:3a:83:37:9a /home/sitaram/.ssh/id_rsa (RSA)
|
|
||||||
2048 d7:23:89:12:5f:22:4f:ad:54:7d:7e:f8:f5:2a:e9:13 /home/sitaram/.ssh/sitaram (RSA)
|
|
||||||
|
|
||||||
If you get only one line (typically the top one), you should ssh-add the
|
|
||||||
other one, using (in my case) `ssh-add ~/.ssh/sitaram`.
|
|
||||||
|
|
||||||
If you get no output, add both of them and check `ssh-add -l` again.
|
|
||||||
|
|
||||||
If this error keeps happening please consider installing [keychain][kch]
|
|
||||||
or something similar, or add these commands to your bash startup scripts.
|
|
||||||
|
|
||||||
[kch]: http://www.gentoo.org/proj/en/keychain/
|
|
||||||
|
|
||||||
* Finally, make sure your `~/.ssh/config` has the required `host gitolite`
|
|
||||||
para (see below for more on this).
|
|
||||||
|
|
||||||
Once these sanity checks have passed, things should be fine. However, if you
|
|
||||||
still have problems, make sure that the "origin" URL in any clones looks like
|
|
||||||
`gitolite:reponame.git`, not `git@server:reponame.git`.
|
|
||||||
|
|
||||||
### explanation
|
|
||||||
|
|
||||||
Here's how it all hangs together.
|
Here's how it all hangs together.
|
||||||
|
|
||||||
|
@ -277,10 +373,37 @@ instance if you have *two* gitolite servers you are administering)?
|
||||||
* now access one server's repos as `gitolite:reponame.git` and the other
|
* now access one server's repos as `gitolite:reponame.git` and the other
|
||||||
server's repos as `gitolite2:reponame.git`.
|
server's repos as `gitolite2:reponame.git`.
|
||||||
|
|
||||||
### further reading
|
### giving shell access to gitolite users
|
||||||
|
|
||||||
While this focused mostly on the client side ssh, you may also want to read
|
We've managed (thanks to an idea from Jesse Keating) to make it possible for a
|
||||||
[this][glb] for a much more detailed explanation of the ssh magic on the
|
single key to allow both gitolite access *and* shell access.
|
||||||
server side.
|
|
||||||
|
This is done by:
|
||||||
|
|
||||||
|
* (**on the server**) listing all such users in a variable called
|
||||||
|
`$SHELL_USERS` in the `~/.gitolite.rc` file. For example:
|
||||||
|
|
||||||
|
$SHELL_USERS = "alice bob";
|
||||||
|
|
||||||
|
(Note the syntax: a space separated list of users in one string variable).
|
||||||
|
|
||||||
|
* (**on your client**) make at least a dummy change to your clone of the
|
||||||
|
gitolite-admin repo and push it.
|
||||||
|
|
||||||
|
**IMPORTANT UPGRADE NOTE**: a previous implementation of this feature worked
|
||||||
|
by adding people to a special group (`@SHELL`) in the *config* file. This
|
||||||
|
meant that anyone with gitolite-admin repo write access could add himself to
|
||||||
|
the `@SHELL` group and push, thus obtaining shell.
|
||||||
|
|
||||||
|
This is not a problem for most setups, but if someone wants to separate these
|
||||||
|
two privileges (the right to push the admin repo and the right to get a shell)
|
||||||
|
then it does pose a problem. Since the "rc" file can only be edited by
|
||||||
|
someone who already has shell access, we now use that instead, even though
|
||||||
|
this forces a change in the syntax.
|
||||||
|
|
||||||
|
To migrate from the old scheme to the new one, add a new variable
|
||||||
|
`$SHELL_USERS` to `~/.gitolite.rc` on the server with the appropriate names in
|
||||||
|
it. **It is best to do this directly on the server *before* upgrading to this
|
||||||
|
version.** (After the upgrade is done and tested you can remove the `@SHELL`
|
||||||
|
lines from the gitolite config file).
|
||||||
|
|
||||||
[glb]: http://sitaramc.github.com/0-installing/9-gitolite-basics.html#IMPORTANT_overview_of_ssh
|
|
||||||
|
|
211
doc/7-install-transcript.mkd
Normal file
211
doc/7-install-transcript.mkd
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
# gitolite install transcript
|
||||||
|
|
||||||
|
This is a *complete* transcript of a full gitolite install, *from scratch*,
|
||||||
|
using brand new userids ("sita" on the client, "git" on the server). Please
|
||||||
|
note that you can use existing userids also, it is not necessary to use
|
||||||
|
dedicated user IDs for this. Also, you don't have to use some *other* server
|
||||||
|
for all this, both server and client can be "localhost" if you like.
|
||||||
|
|
||||||
|
Please note that this entire transcript can be summarised as:
|
||||||
|
|
||||||
|
* create users on client and server (optional)
|
||||||
|
* get pubkey access to server from client (`ssh-copy-id` or manual eqvt)
|
||||||
|
* run one command ***on client*** (`gl-easy-install`)
|
||||||
|
|
||||||
|
...and only that last step is actually gitolite. In fact, the bulk of the
|
||||||
|
transcript is **non**-gitolite stuff :)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### create userids on server and client (optional)
|
||||||
|
|
||||||
|
Client side: add user, give him a password
|
||||||
|
|
||||||
|
sita-lt:~ # useradd sita
|
||||||
|
|
||||||
|
sita-lt:~ # passwd sita
|
||||||
|
Changing password for user sita.
|
||||||
|
New UNIX password:
|
||||||
|
Retype new UNIX password:
|
||||||
|
passwd: all authentication tokens updated successfully.
|
||||||
|
|
||||||
|
Server side: (log on to server, then) add user, give it a password
|
||||||
|
|
||||||
|
sita-lt:~ # ssh sitaram@server
|
||||||
|
sitaram@server's password:
|
||||||
|
Last login: Fri Dec 18 20:25:06 2009
|
||||||
|
-bash-3.2$ su -
|
||||||
|
Password:
|
||||||
|
|
||||||
|
sita-sv:~ # useradd git
|
||||||
|
|
||||||
|
sita-sv:~ # passwd git
|
||||||
|
Changing password for user git.
|
||||||
|
New UNIX password:
|
||||||
|
Retype new UNIX password:
|
||||||
|
passwd: all authentication tokens updated successfully.
|
||||||
|
|
||||||
|
Server side: allow ssh access to "git" user
|
||||||
|
|
||||||
|
This is done by editing the sshd config file and adding "git" to the
|
||||||
|
"AllowUsers" list (the grep command is just confirming the change we made,
|
||||||
|
because I'm not showing the actual "vi" session):
|
||||||
|
|
||||||
|
sita-sv:~ # vim /etc/ssh/sshd_config
|
||||||
|
|
||||||
|
sita-sv:~ # grep -i allowusers /etc/ssh/sshd_config
|
||||||
|
AllowUsers sitaram git
|
||||||
|
|
||||||
|
sita-sv:~ # service sshd restart
|
||||||
|
Stopping sshd: [ OK ]
|
||||||
|
Starting sshd: [ OK ]
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### get pubkey access from client to server
|
||||||
|
|
||||||
|
This involves creating a keypair for yourself (using `ssh-keygen`), and
|
||||||
|
copying the public part of that keypair to the `~/.ssh/authorized_keys` file
|
||||||
|
on the server (using `ssh-copy-id`, if you're on Linux, or the manual method
|
||||||
|
described in the `ssh-copy-id` section in `doc/3-faq-tips-etc.mkd`).
|
||||||
|
|
||||||
|
sita-lt:~ $ su - sita
|
||||||
|
Password:
|
||||||
|
|
||||||
|
sita@sita-lt:~ $ ssh-keygen
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/home/sita/.ssh/id_rsa):
|
||||||
|
Created directory '/home/sita/.ssh'.
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in /home/sita/.ssh/id_rsa.
|
||||||
|
Your public key has been saved in /home/sita/.ssh/id_rsa.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
8a:e0:60:1b:04:58:68:50:a4:d7:d0:3a:a5:2d:bf:0a sita@sita-lt.atc.tcs.com
|
||||||
|
The key's randomart image is:
|
||||||
|
+--[ RSA 2048]----+
|
||||||
|
|===. |
|
||||||
|
|+o oo |
|
||||||
|
|o..=. |
|
||||||
|
|..= . |
|
||||||
|
|.o.+ S |
|
||||||
|
|.oo... . |
|
||||||
|
|E.. ... |
|
||||||
|
| . . |
|
||||||
|
| .. |
|
||||||
|
+-----------------+
|
||||||
|
|
||||||
|
sita@sita-lt:~ $ ssh-copy-id -i ~/.ssh/id_rsa git@server
|
||||||
|
git@server's password:
|
||||||
|
/usr/bin/xauth: creating new authority file /home/git/.Xauthority
|
||||||
|
Now try logging into the machine, with "ssh 'git@server'", and check in:
|
||||||
|
|
||||||
|
.ssh/authorized_keys
|
||||||
|
|
||||||
|
to make sure we haven't added extra keys that you weren't expecting.
|
||||||
|
|
||||||
|
Double check to make sure you can log on to `git@server` without a password:
|
||||||
|
|
||||||
|
sita@sita-lt:~ $ ssh git@server pwd
|
||||||
|
/home/git
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### get gitolite source
|
||||||
|
|
||||||
|
sita@sita-lt:~ $ git clone git://github.com/sitaramc/gitolite gitolite-source
|
||||||
|
Initialized empty Git repository in /home/sita/gitolite-source/.git/
|
||||||
|
remote: Counting objects: 1157, done.
|
||||||
|
remote: Compressing objects: 100% (584/584), done.
|
||||||
|
remote: Total 1157 (delta 756), reused 912 (delta 562)
|
||||||
|
Receiving objects: 100% (1157/1157), 270.08 KiB | 61 KiB/s, done.
|
||||||
|
Resolving deltas: 100% (756/756), done.
|
||||||
|
|
||||||
|
### install gitolite
|
||||||
|
|
||||||
|
Note that gitolite is installed from the *client*. The `easy-install` script
|
||||||
|
runs on the client but installs gitolite on the server!
|
||||||
|
|
||||||
|
sita@sita-lt:~ $ cd gitolite-source/src
|
||||||
|
|
||||||
|
<font color="red"> **This is the only gitolite specific command in a typical
|
||||||
|
install sequence**. </font> Run it without any arguments to see a usage
|
||||||
|
message. Run it without the `-q` to get a more verbose, pause-at-every-step,
|
||||||
|
install mode that allows you to change the defaults etc.
|
||||||
|
|
||||||
|
|
||||||
|
sita@sita-lt:src $ ./gl-easy-install -q git server sitaram
|
||||||
|
you are upgrading (or installing first-time) to v0.95-38-gb0ce84d
|
||||||
|
setting up keypair...
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in /home/sita/.ssh/sitaram.
|
||||||
|
Your public key has been saved in /home/sita/.ssh/sitaram.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
2a:8e:88:42:36:7e:71:e8:cc:ff:4c:54:64:8e:cf:19 sita@sita-lt.atc.tcs.com
|
||||||
|
The key's randomart image is:
|
||||||
|
+--[ RSA 2048]----+
|
||||||
|
| o |
|
||||||
|
| = |
|
||||||
|
| . E |
|
||||||
|
| + o |
|
||||||
|
| . .S+ |
|
||||||
|
| + o ... |
|
||||||
|
|+ = + .. |
|
||||||
|
|oo B .o |
|
||||||
|
|+ o o..o |
|
||||||
|
+-----------------+
|
||||||
|
creating gitolite para in ~/.ssh/config...
|
||||||
|
finding/creating gitolite rc...
|
||||||
|
installing/upgrading...
|
||||||
|
Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/
|
||||||
|
Initialized empty Git repository in /home/git/repositories/testing.git/
|
||||||
|
Pseudo-terminal will not be allocated because stdin is not a terminal.
|
||||||
|
fatal: No HEAD commit to compare with (yet)
|
||||||
|
[master (root-commit) 2f40d4b] start
|
||||||
|
2 files changed, 13 insertions(+), 0 deletions(-)
|
||||||
|
create mode 100644 conf/gitolite.conf
|
||||||
|
create mode 100644 keydir/sitaram.pub
|
||||||
|
cloning gitolite-admin repo...
|
||||||
|
Initialized empty Git repository in /home/sita/gitolite-admin/.git/
|
||||||
|
remote: Counting objects: 6, done.
|
||||||
|
remote: Compressing objects: 100% (4/4), done.
|
||||||
|
remote: Total 6 (delta 0), reused 0 (delta 0)
|
||||||
|
Receiving objects: 100% (6/6), done.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
done!
|
||||||
|
|
||||||
|
Reminder:
|
||||||
|
*Your* URL for cloning any repo on this server will be
|
||||||
|
gitolite:reponame.git
|
||||||
|
*Other* users you set up will have to use
|
||||||
|
git@server:reponame.git
|
||||||
|
|
||||||
|
If this is your first time installing gitolite, please also:
|
||||||
|
tail -31 ./gl-easy-install
|
||||||
|
for next steps.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### examine what you have
|
||||||
|
|
||||||
|
sita@sita-lt:src $ cd ~/gitolite-admin/
|
||||||
|
|
||||||
|
sita@sita-lt:gitolite-admin $ git --no-pager log --stat
|
||||||
|
commit 2f40d4bb80d424dc39aae5d0973f8c1b2e395666
|
||||||
|
Author: git <git@sita-lt.atc.tcs.com>
|
||||||
|
Date: Thu Dec 24 21:39:15 2009 +0530
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
conf/gitolite.conf | 12 ++++++++++++
|
||||||
|
keydir/sitaram.pub | 1 +
|
||||||
|
2 files changed, 13 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
And that's really all. Add keys to keydir here, edit conf/gitolite.conf as
|
||||||
|
needed, then add, commit, and push the changes to the server. Try out that
|
||||||
|
`tail -31 ./gl-easy-install` too :)
|
|
@ -4,28 +4,5 @@
|
||||||
# (the GL_ADMINDIR env var would have been set by gl-auth-command)
|
# (the GL_ADMINDIR env var would have been set by gl-auth-command)
|
||||||
GIT_WORK_TREE=$GL_ADMINDIR git checkout -f master
|
GIT_WORK_TREE=$GL_ADMINDIR git checkout -f master
|
||||||
|
|
||||||
# remove all fragments. otherwise, you get spurious error messages when you
|
|
||||||
# take away someone's delegation in the main config but the fragment is still
|
|
||||||
# hanging around. The ones that are valid will get re-created anyway
|
|
||||||
rm -rf $GL_ADMINDIR/conf/fragments
|
|
||||||
# collect all the delegated fragments
|
|
||||||
mkdir $GL_ADMINDIR/conf/fragments
|
|
||||||
for br in `git for-each-ref --format='%(refname:short)'`
|
|
||||||
do
|
|
||||||
# skip master (duh!)
|
|
||||||
[ "$br" = "master" ] && continue
|
|
||||||
|
|
||||||
# all other branches *should* contain a file called <branchname>.conf
|
|
||||||
# inside conf/fragments; if so copy it
|
|
||||||
if git show $br:conf/fragments/$br.conf > /dev/null 2>&1
|
|
||||||
then
|
|
||||||
git show $br:conf/fragments/$br.conf > $GL_ADMINDIR/conf/fragments/$br.conf
|
|
||||||
echo "(extracted $br conf; `wc -l < $GL_ADMINDIR/conf/fragments/$br.conf` lines)"
|
|
||||||
else
|
|
||||||
echo " ***** ERROR *****"
|
|
||||||
echo " branch $br does not contain conf/fragments/$br.conf"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
cd $GL_ADMINDIR
|
cd $GL_ADMINDIR
|
||||||
$GL_BINDIR/gl-compile-conf
|
$GL_BINDIR/gl-compile-conf
|
||||||
|
|
|
@ -96,7 +96,7 @@ if ($cmd eq 'info') {
|
||||||
# git-receive-pack 'reponame.git'
|
# git-receive-pack 'reponame.git'
|
||||||
# including the single quotes
|
# including the single quotes
|
||||||
|
|
||||||
my ($verb, $repo) = ($cmd =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:.git)?'/);
|
my ($verb, $repo) = ($cmd =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/);
|
||||||
unless ( $verb and ( $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
|
unless ( $verb and ( $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
|
||||||
# if the user is allowed a shell, just run the command
|
# if the user is allowed a shell, just run the command
|
||||||
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND} if $shell_allowed;
|
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND} if $shell_allowed;
|
||||||
|
|
|
@ -52,7 +52,7 @@ $Data::Dumper::Sortkeys = 1;
|
||||||
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
||||||
|
|
||||||
# these are set by the "rc" file
|
# these are set by the "rc" file
|
||||||
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH);
|
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH, $SHELL_USERS);
|
||||||
# and these are set by gitolite.pm
|
# and these are set by gitolite.pm
|
||||||
our ($REPONAME_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN);
|
our ($REPONAME_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN);
|
||||||
|
|
||||||
|
@ -162,13 +162,13 @@ sub parse_conf_file
|
||||||
my @repos;
|
my @repos;
|
||||||
while (<$conf_fh>)
|
while (<$conf_fh>)
|
||||||
{
|
{
|
||||||
|
# kill comments, but take care of "#" inside *simple* strings
|
||||||
|
s/^((".*?"|[^#"])*)#.*/$1/;
|
||||||
# normalise whitespace; keeps later regexes very simple
|
# normalise whitespace; keeps later regexes very simple
|
||||||
s/=/ = /;
|
s/=/ = /;
|
||||||
s/\s+/ /g;
|
s/\s+/ /g;
|
||||||
s/^ //;
|
s/^ //;
|
||||||
s/ $//;
|
s/ $//;
|
||||||
# kill comments
|
|
||||||
s/\s*#.*//;
|
|
||||||
# and blank lines
|
# and blank lines
|
||||||
next unless /\S/;
|
next unless /\S/;
|
||||||
|
|
||||||
|
@ -200,9 +200,11 @@ sub parse_conf_file
|
||||||
|
|
||||||
# if no ref is given, this PERM applies to all refs
|
# if no ref is given, this PERM applies to all refs
|
||||||
@refs = qw(refs/.*) unless @refs;
|
@refs = qw(refs/.*) unless @refs;
|
||||||
# fully qualify refs that dont start with "refs/" or "PATH/";
|
# deprecation warning
|
||||||
|
map { warn "WARNING: old syntax 'PATH/' found; please use new syntax 'NAME/'\n" if s(^PATH/)(NAME/) } @refs;
|
||||||
|
# fully qualify refs that dont start with "refs/" or "NAME/";
|
||||||
# prefix them with "refs/heads/"
|
# prefix them with "refs/heads/"
|
||||||
@refs = map { m(^(refs|PATH)/) or s(^)(refs/heads/); $_ } @refs;
|
@refs = map { m(^(refs|NAME)/) or s(^)(refs/heads/); $_ } @refs;
|
||||||
|
|
||||||
# expand the user list, unless it is just "@all"
|
# expand the user list, unless it is just "@all"
|
||||||
@users = expand_list ( @users )
|
@users = expand_list ( @users )
|
||||||
|
@ -239,13 +241,13 @@ sub parse_conf_file
|
||||||
# for 2nd level check, store each "ref, perms" pair in order
|
# for 2nd level check, store each "ref, perms" pair in order
|
||||||
for my $ref (@refs)
|
for my $ref (@refs)
|
||||||
{
|
{
|
||||||
# checking PATH based restrictions is expensive for
|
# checking NAME based restrictions is expensive for
|
||||||
# the update hook (see the changes to src/hooks/update
|
# the update hook (see the changes to src/hooks/update
|
||||||
# in this commit for why) so we would *very* much like
|
# in this commit for why) so we would *very* much like
|
||||||
# to avoid doing it for the large majority of repos
|
# to avoid doing it for the large majority of repos
|
||||||
# that do *not* use PATH limits. Setting a flag that
|
# that do *not* use NAME limits. Setting a flag that
|
||||||
# can be checked right away will help us do that
|
# can be checked right away will help us do that
|
||||||
$repos{$repo}{PATH_LIMITS} = 1 if $ref =~ /^PATH\//;
|
$repos{$repo}{NAME_LIMITS} = 1 if $ref =~ /^NAME\//;
|
||||||
push @{ $repos{$repo}{$user} }, { $ref => $perms }
|
push @{ $repos{$repo}{$user} }, { $ref => $perms }
|
||||||
unless $rurp_seen{$repo}{$user}{$ref}{$perms}++;
|
unless $rurp_seen{$repo}{$user}{$ref}{$perms}++;
|
||||||
}
|
}
|
||||||
|
@ -262,6 +264,16 @@ sub parse_conf_file
|
||||||
$repo_config{$repo}{$key} = $value;
|
$repo_config{$repo}{$key} = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# include
|
||||||
|
elsif (/^include "(.+)"/)
|
||||||
|
{
|
||||||
|
my $file = $1;
|
||||||
|
$file = "$GL_ADMINDIR/conf/$file" unless $file =~ /^\//;
|
||||||
|
die "$WARN $fragment attempting to include configuration\n" if $fragment ne 'master';
|
||||||
|
die "$ABRT included file not found: '$file'\n" unless -f $file;
|
||||||
|
|
||||||
|
parse_conf_file($file, $fragment);
|
||||||
|
}
|
||||||
# very simple syntax for the gitweb description of repo; one of:
|
# very simple syntax for the gitweb description of repo; one of:
|
||||||
# reponame = "some description string"
|
# reponame = "some description string"
|
||||||
# reponame "owner name" = "some description string"
|
# reponame "owner name" = "some description string"
|
||||||
|
@ -446,14 +458,20 @@ for my $pubkey (glob("*"))
|
||||||
print STDERR "WARNING: pubkey $pubkey exists but user $user not in config\n"
|
print STDERR "WARNING: pubkey $pubkey exists but user $user not in config\n"
|
||||||
unless $user_list{$user};
|
unless $user_list{$user};
|
||||||
$user_list{$user} = 'has pubkey';
|
$user_list{$user} = 'has pubkey';
|
||||||
if ($groups{'@SHELL'}{$user}) {
|
# apparently some pubkeys don't end in a newline...
|
||||||
|
my $pubkey_content = `cat $pubkey`;
|
||||||
|
$pubkey_content =~ s/\s*$/\n/;
|
||||||
|
# don't trust files with multiple lines (i.e., something after a newline)
|
||||||
|
if ($pubkey_content =~ /\n./)
|
||||||
|
{
|
||||||
|
print STDERR "WARNING: a pubkey file can only have one line (key); ignoring $pubkey\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($SHELL_USERS and $SHELL_USERS =~ /(^|\s)$user(\s|$)/) {
|
||||||
print $newkeys_fh "command=\"$AUTH_COMMAND -s $user\",$AUTH_OPTIONS ";
|
print $newkeys_fh "command=\"$AUTH_COMMAND -s $user\",$AUTH_OPTIONS ";
|
||||||
} else {
|
} else {
|
||||||
print $newkeys_fh "command=\"$AUTH_COMMAND $user\",$AUTH_OPTIONS,no-pty ";
|
print $newkeys_fh "command=\"$AUTH_COMMAND $user\",$AUTH_OPTIONS,no-pty ";
|
||||||
}
|
}
|
||||||
# apparently some pubkeys don't end in a newline...
|
|
||||||
my $pubkey_content = `cat $pubkey`;
|
|
||||||
$pubkey_content =~ s/\s*$/\n/;
|
|
||||||
print $newkeys_fh $pubkey_content;
|
print $newkeys_fh $pubkey_content;
|
||||||
}
|
}
|
||||||
# lint check 3; a little more severe than the first two I guess...
|
# lint check 3; a little more severe than the first two I guess...
|
||||||
|
|
|
@ -302,12 +302,21 @@ copy_gl() {
|
||||||
prompt " ...trying to reuse existing rc" \
|
prompt " ...trying to reuse existing rc" \
|
||||||
"Oh hey... you already had a '.gitolite.rc' file on the server.
|
"Oh hey... you already had a '.gitolite.rc' file on the server.
|
||||||
Let's see if we can use that instead of the default one..."
|
Let's see if we can use that instead of the default one..."
|
||||||
sort < $tmpgli/.gitolite.rc | perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' > $tmpgli/glrc.old
|
< $tmpgli/.gitolite.rc perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' | sort > $tmpgli/glrc.old
|
||||||
sort < conf/example.gitolite.rc | perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' > $tmpgli/glrc.new
|
< conf/example.gitolite.rc perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' | sort > $tmpgli/glrc.new
|
||||||
if diff -u $tmpgli/glrc.old $tmpgli/glrc.new
|
# msysgit doesn't have "comm". diff is not ideal for our purposes
|
||||||
|
# because we only care about differences in one direction, but we'll
|
||||||
|
# have to make do...
|
||||||
|
set +e
|
||||||
|
diff -u $tmpgli/glrc.old $tmpgli/glrc.new | grep '^+.*\$' > $tmpgli/glrc.comm13
|
||||||
|
set -e
|
||||||
|
if [[ ! -s $tmpgli/glrc.comm13 ]]
|
||||||
then
|
then
|
||||||
[[ $quiet == -q ]] || ${VISUAL:-${EDITOR:-vi}} $tmpgli/.gitolite.rc
|
[[ $quiet == -q ]] || ${VISUAL:-${EDITOR:-vi}} $tmpgli/.gitolite.rc
|
||||||
else
|
else
|
||||||
|
echo new variables found in rc file:
|
||||||
|
cat $tmpgli/glrc.comm13
|
||||||
|
echo
|
||||||
# MANUAL: if you're upgrading, read the instructions below and
|
# MANUAL: if you're upgrading, read the instructions below and
|
||||||
# manually make sure your final ~/.gitolite.rc has both your existing
|
# manually make sure your final ~/.gitolite.rc has both your existing
|
||||||
# customisations as well as any new variables that the new version of
|
# customisations as well as any new variables that the new version of
|
||||||
|
@ -339,6 +348,8 @@ run_install() {
|
||||||
if ssh -p $port $user@$host cat $GL_ADMINDIR/conf/gitolite.conf &> /dev/null
|
if ssh -p $port $user@$host cat $GL_ADMINDIR/conf/gitolite.conf &> /dev/null
|
||||||
then
|
then
|
||||||
upgrade=1
|
upgrade=1
|
||||||
|
ssh -p $port $user@$host cat $GL_ADMINDIR/conf/gitolite.conf 2> /dev/null | grep '@SHELL' &&
|
||||||
|
prompt "" "$v_at_shell_bwi"
|
||||||
[[ -n $admin_name ]] && echo -e "\n *** WARNING ***: looks like an upgrade... ignoring argument '$admin_name'"
|
[[ -n $admin_name ]] && echo -e "\n *** WARNING ***: looks like an upgrade... ignoring argument '$admin_name'"
|
||||||
else
|
else
|
||||||
[[ -z $admin_name ]] && die " *** ERROR ***: doesn't look like an upgrade, so I need a name for the admin"
|
[[ -z $admin_name ]] && die " *** ERROR ***: doesn't look like an upgrade, so I need a name for the admin"
|
||||||
|
@ -361,7 +372,6 @@ run_install() {
|
||||||
# MANUAL: setup the initial config file. Edit $GL_ADMINDIR/conf/gitolite.conf
|
# MANUAL: setup the initial config file. Edit $GL_ADMINDIR/conf/gitolite.conf
|
||||||
# and add at least the following lines to it:
|
# and add at least the following lines to it:
|
||||||
|
|
||||||
# @SHELL = sitaram
|
|
||||||
# repo gitolite-admin
|
# repo gitolite-admin
|
||||||
# RW+ = sitaram
|
# RW+ = sitaram
|
||||||
|
|
||||||
|
@ -369,8 +379,6 @@ initial_conf_key() {
|
||||||
echo "#gitolite conf
|
echo "#gitolite conf
|
||||||
# please see conf/example.conf for details on syntax and features
|
# please see conf/example.conf for details on syntax and features
|
||||||
|
|
||||||
@SHELL = $admin_name
|
|
||||||
|
|
||||||
repo gitolite-admin
|
repo gitolite-admin
|
||||||
RW+ = $admin_name
|
RW+ = $admin_name
|
||||||
|
|
||||||
|
@ -401,7 +409,6 @@ setup_pta() {
|
||||||
# Substitute $GL_ADMINDIR and $REPO_BASE appropriately. Note there is no
|
# Substitute $GL_ADMINDIR and $REPO_BASE appropriately. Note there is no
|
||||||
# space around the "=" in the second and third lines.
|
# space around the "=" in the second and third lines.
|
||||||
|
|
||||||
git ls-remote gitolite:gitolite-admin
|
|
||||||
echo "cd $REPO_BASE/gitolite-admin.git
|
echo "cd $REPO_BASE/gitolite-admin.git
|
||||||
GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir
|
GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir
|
||||||
GIT_WORK_TREE=$GL_ADMINDIR git diff --cached --quiet || GIT_WORK_TREE=$GL_ADMINDIR git commit -am start
|
GIT_WORK_TREE=$GL_ADMINDIR git diff --cached --quiet || GIT_WORK_TREE=$GL_ADMINDIR git commit -am start
|
||||||
|
@ -524,7 +531,7 @@ v_upgrade_glrc="
|
||||||
looks like you're upgrading, and there are some new rc variables that this
|
looks like you're upgrading, and there are some new rc variables that this
|
||||||
version is expecting that your old rc file doesn't have.
|
version is expecting that your old rc file doesn't have.
|
||||||
|
|
||||||
I'm going to run your editor with two filenames. The first is the example
|
I'm going to run your \\\$EDITOR with two filenames. The first is the example
|
||||||
file from this gitolite version. It will have a block (code and comments) for
|
file from this gitolite version. It will have a block (code and comments) for
|
||||||
each of the variables shown above with a '+' sign.
|
each of the variables shown above with a '+' sign.
|
||||||
|
|
||||||
|
@ -534,7 +541,7 @@ it.
|
||||||
|
|
||||||
This is necessary; please dont skip this!
|
This is necessary; please dont skip this!
|
||||||
|
|
||||||
[It's upto you to figure out how your editor handles 2 filename arguments,
|
[It's upto you to figure out how your \\\$EDITOR handles 2 filename arguments,
|
||||||
switch between them, copy lines, etc ;-)]
|
switch between them, copy lines, etc ;-)]
|
||||||
"
|
"
|
||||||
|
|
||||||
|
@ -544,6 +551,17 @@ next set of command outputs coming up. They're only relevant for a manual
|
||||||
install, not this one...
|
install, not this one...
|
||||||
"
|
"
|
||||||
|
|
||||||
|
v_at_shell_bwi="
|
||||||
|
you are using the @SHELL feature in your gitolite config. This feature has
|
||||||
|
now changed in a backward incompatible way; see doc/6-ssh-troubleshooting.mkd
|
||||||
|
for information on migrating this to the new syntax.
|
||||||
|
|
||||||
|
DO NOT hit enter unless you have understood that information and properly
|
||||||
|
migrated your setup, or you are sure you have shell access to the server
|
||||||
|
through some other means than the $admin_name key.
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
v_done="
|
v_done="
|
||||||
done!
|
done!
|
||||||
|
|
||||||
|
|
|
@ -65,12 +65,12 @@ push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{'@all'} || [] };
|
||||||
# prepare the list of refs to be checked
|
# prepare the list of refs to be checked
|
||||||
|
|
||||||
# previously, we just checked $ref -- the ref being updated, which is passed
|
# previously, we just checked $ref -- the ref being updated, which is passed
|
||||||
# to us by git (see man githooks). Now we also have to treat each PATH being
|
# to us by git (see man githooks). Now we also have to treat each NAME being
|
||||||
# updated as a potential "ref" and check that, if PATH-based restrictions have
|
# updated as a potential "ref" and check that, if NAME-based restrictions have
|
||||||
# been specified
|
# been specified
|
||||||
|
|
||||||
my @refs = ($ref); # the first ref to check is the real one
|
my @refs = ($ref); # the first ref to check is the real one
|
||||||
if (exists $repos{$ENV{GL_REPO}}{PATH_LIMITS}) {
|
if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
||||||
# this is special to git -- the hash of an empty tree
|
# this is special to git -- the hash of an empty tree
|
||||||
my $empty='4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
my $empty='4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
||||||
# well they're not really "trees" but $empty is indeed the empty tree so
|
# well they're not really "trees" but $empty is indeed the empty tree so
|
||||||
|
@ -78,7 +78,7 @@ if (exists $repos{$ENV{GL_REPO}}{PATH_LIMITS}) {
|
||||||
# diff' only wants trees
|
# diff' only wants trees
|
||||||
my $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
|
my $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
|
||||||
my $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
|
my $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
|
||||||
push @refs, map { chomp; s/^/PATH\//; $_; } `git diff --name-only $oldtree $newtree`;
|
push @refs, map { chomp; s/^/NAME\//; $_; } `git diff --name-only $oldtree $newtree`;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $refex = '';
|
my $refex = '';
|
||||||
|
@ -100,7 +100,7 @@ sub check_ref {
|
||||||
for my $ar (@allowed_refs) {
|
for my $ar (@allowed_refs) {
|
||||||
$refex = (keys %$ar)[0];
|
$refex = (keys %$ar)[0];
|
||||||
# refex? sure -- a regex to match a ref against :)
|
# refex? sure -- a regex to match a ref against :)
|
||||||
next unless $ref =~ /$refex/;
|
next unless $ref =~ /^$refex/;
|
||||||
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
|
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
|
||||||
|
|
||||||
# as far as *this* ref is concerned we're ok
|
# as far as *this* ref is concerned we're ok
|
||||||
|
@ -111,7 +111,7 @@ sub check_ref {
|
||||||
|
|
||||||
# and in this version, we have many "refs" to check. The one we print in the
|
# and in this version, we have many "refs" to check. The one we print in the
|
||||||
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
||||||
# while all the rest (if they exist) are like PATH/something. So we do the
|
# while all the rest (if they exist) are like NAME/something. So we do the
|
||||||
# first one separately to capture it, then run the rest (if any)
|
# first one separately to capture it, then run the rest (if any)
|
||||||
my $log_refex = check_ref(shift @refs);
|
my $log_refex = check_ref(shift @refs);
|
||||||
check_ref($_) for @refs;
|
check_ref($_) for @refs;
|
||||||
|
|
100
src/sshkeys-lint
Executable file
100
src/sshkeys-lint
Executable file
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
our (%users, %linenos);
|
||||||
|
|
||||||
|
&usage unless $ARGV[0] and -f $ARGV[0];
|
||||||
|
my @authlines = &filelines($ARGV[0]);
|
||||||
|
my $lineno = 0;
|
||||||
|
for (@authlines)
|
||||||
|
{
|
||||||
|
$lineno++;
|
||||||
|
if (/^# gitolite start/ .. /^# gitolite end/) {
|
||||||
|
warn "line $lineno: non-gitolite key found in gitolite section" if /ssh-rsa|ssh-dss/ and not /command=.*gl-auth-command/;
|
||||||
|
} else {
|
||||||
|
warn "line $lineno: gitolite key found outside gitolite section" if /command=.*gl-auth-command/;
|
||||||
|
}
|
||||||
|
next if /\# gitolite (start|end)/;
|
||||||
|
die "line $lineno: unrecognised line\n" unless /^(?:command=".*gl-auth-command (\S+?)"\S+ )?(?:ssh-rsa|ssh-dss) (\S+)/;
|
||||||
|
my ($user, $key) = ($1 || '', $2);
|
||||||
|
if ($linenos{$key}) {
|
||||||
|
warn "authkeys file line $lineno is repeat of line $linenos{$key}, will be ignored by server sshd\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$linenos{$key} = $lineno;
|
||||||
|
$users{$key} = ($user ? "maps to gitolite user $user" : "gets you a command line");
|
||||||
|
}
|
||||||
|
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
# all *.pub in current dir should be exactly one line, starting with ssh-rsa
|
||||||
|
# or ssh-dss
|
||||||
|
|
||||||
|
my @pubkeys = glob("*.pub");
|
||||||
|
die "no *.pub files here\n" unless @pubkeys;
|
||||||
|
for my $pub (@pubkeys) {
|
||||||
|
my @lines = &filelines($pub);
|
||||||
|
die "$pub has more than one line\n" if @lines > 1;
|
||||||
|
die "$pub does not start with ssh-rsa or ssh-dss\n" unless $lines[0] =~ /^(?:ssh-rsa|ssh-dss) (\S+)/;
|
||||||
|
my $key = $1;
|
||||||
|
if ($users{$key}) {
|
||||||
|
print "$pub $users{$key}\n";
|
||||||
|
} else {
|
||||||
|
print "$pub has NO ACCESS to the server\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print <<INFO;
|
||||||
|
|
||||||
|
Git operations using a pubkey that gets you a command line will BYPASS
|
||||||
|
gitolite completely. This means:
|
||||||
|
|
||||||
|
- using "git clone git\@server:reponame" will get you the "does not appear to
|
||||||
|
be a git repository" message
|
||||||
|
- using "git clone git\@server:repositories/reponame" [assuming default value
|
||||||
|
of \$REPO_BASE) will work but subsequent push will fail
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Now you know what pubkey gets you what access.
|
||||||
|
|
||||||
|
To see what key is *actually* being used when you run your commands, try "ssh
|
||||||
|
-v git\@server" or "ssh -v gitolite", and look for a line saying "Offering
|
||||||
|
public key". If there are more than one such lines, the last one is what
|
||||||
|
counts.
|
||||||
|
|
||||||
|
If at any time you are asked for a password (password, not passphrase; see
|
||||||
|
doc/6 for the difference, if needed), then none of this applies anyway.
|
||||||
|
|
||||||
|
INFO
|
||||||
|
|
||||||
|
sub filelines
|
||||||
|
{
|
||||||
|
my $f;
|
||||||
|
my $fn = shift;
|
||||||
|
open ($f, "<", $fn) or die "open $fn failed: $!\n";
|
||||||
|
return <$f>;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub usage
|
||||||
|
{
|
||||||
|
print STDERR <<EOF;
|
||||||
|
|
||||||
|
On your *client*:
|
||||||
|
|
||||||
|
- copy the server's ~/.ssh/authorized_keys file to your *client*'s
|
||||||
|
/tmp/foo (maybe using "scp" or whatever)
|
||||||
|
|
||||||
|
- cd to the ~/.ssh directory (which contains all the pub keys this client
|
||||||
|
can use)
|
||||||
|
|
||||||
|
- run "$0 /tmp/foo"
|
||||||
|
|
||||||
|
Note: people who have so many keypairs they keep them in *sub*-directories of
|
||||||
|
~/.ssh [you know who you are ;-)] can figure it out themselves; you clearly
|
||||||
|
know enough about ssh not to need my help!
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 1;
|
||||||
|
}
|
Loading…
Reference in a new issue