Merge remote branch 'origin/pu'

This commit is contained in:
Sitaram Chamarty 2010-02-01 10:44:48 +05:30
commit 90fed77927
13 changed files with 669 additions and 157 deletions

View file

@ -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

View file

@ -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.

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View 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 :)

View file

@ -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

View file

@ -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;

View file

@ -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...

View file

@ -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!

View file

@ -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
View 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;
}