diff options
author | Christian Ruppert <idl0r@gentoo.org> | 2011-02-15 17:38:31 +0100 |
---|---|---|
committer | Christian Ruppert <idl0r@gentoo.org> | 2011-02-15 17:38:31 +0100 |
commit | 231d7fb70ec7acf410fe78e379383c8da021f8dd (patch) | |
tree | aee552def6e3bf2983e3ce394761f11d1875b548 | |
parent | Add missing curly bracket (diff) | |
parent | v1.5.9 (diff) | |
download | gitolite-gentoo-231d7fb70ec7acf410fe78e379383c8da021f8dd.tar.gz gitolite-gentoo-231d7fb70ec7acf410fe78e379383c8da021f8dd.tar.bz2 gitolite-gentoo-231d7fb70ec7acf410fe78e379383c8da021f8dd.zip |
Merge branch 'upstream'gitolite-gentoo-1.5.9
Conflicts:
conf/example.gitolite.rc
src/gl-auth-command
32 files changed, 1407 insertions, 505 deletions
diff --git a/conf/example.conf b/conf/example.conf index 99ba483..27f99cd 100644 --- a/conf/example.conf +++ b/conf/example.conf @@ -162,9 +162,6 @@ repo git # defined as either permitting the operation you're attempting (`W` or `+`), # which results in success, or a "deny" (`-`), which results in failure. # (As before, a fallthrough also results in failure). -# -# - do not use `@all` when your config has any deny rules; it won't work as -# you probably expect it to! # in the example above, you cannot easily say "anyone can write any tag, # except version tags can only be written by junio". The following might look diff --git a/conf/example.gitolite.rc b/conf/example.gitolite.rc index 211b7cb..6f57994 100644 --- a/conf/example.gitolite.rc +++ b/conf/example.gitolite.rc @@ -1,320 +1,86 @@ -# paths and configuration variables for gitolite +# configuration variables for gitolite -# please read comments before editing +# PLEASE READ THE DOCUMENTATION BEFORE EDITING OR ASKING QUESTIONS +# ( http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd ) # this file is meant to be pulled into a perl program using "do" or "require". - # You do NOT need to know perl to edit the paths; it should be fairly # self-explanatory and easy to maintain perl syntax :-) -# -------------------------------------- -# Do not change the next two lines unless you know what you're doing -# $GL_PACKAGE_CONF = ""; -# $GL_PACKAGE_HOOKS = ""; - -# -------------------------------------- -# MIRRORING SUPPORT - -# $GL_SLAVE_MODE = 0; -# $ENV{GL_SLAVES} = 'gitolite@server2 gitolite@server3'; -# PLEASE USE SINGLE QUOTES ABOVE, NOT DOUBLE QUOTES - -# see doc/mirroring.mkd for details - -# -------------------------------------- - -# this is where the repos go. If you provide a relative path (not starting -# with "/"), it's relative to your $HOME. You may want to put in something -# like "/bigdisk" or whatever if your $HOME is too small for the repos, for -# example - -$REPO_BASE="repositories"; - -# the default umask for repositories is 0077; change this if you run stuff -# like gitweb and find it can't read the repos. Please note the syntax; the -# leading 0 is required - -$REPO_UMASK = 0077; # gets you 'rwx------' -# $REPO_UMASK = 0027; # gets you 'rwxr-x---' -# $REPO_UMASK = 0022; # gets you 'rwxr-xr-x' - -# part of the setup of gitweb is a variable called $projects_list (please see -# gitweb documentation for more on this). Set this to the same value: - -$PROJECTS_LIST = $ENV{HOME} . "/projects.list"; - -# giving access to @all users (as in "R = @all") in the config normally does -# *not* include the special users "gitweb" and "daemon". If you want @all to -# include these two users, set this variable: - -# $GL_ALL_INCLUDES_SPECIAL = 0; - -# -------------------------------------- - -# I see no reason anyone may want to change the gitolite admin directory, but -# feel free to do so. However, please note that it *must* be an *absolute* -# path (i.e., starting with a "/" character) - -# gitolite admin directory, files, etc - +# ------------------------------------------------------------------------------ +# VARIABLES THAT SHOULD NOT BE TOUCHED AT ALL. EVER. +# ------------------------------------------------------------------------------ $GL_ADMINDIR=$ENV{HOME} . "/.gitolite"; - -# -------------------------------------- - -# templates for location of the log files and format of their names - -# I prefer this template (note the %y and %m placeholders) -# it produces files like `~/.gitolite/logs/gitolite-2009-09.log` - -$GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m.log"; - -# other choices are below, or you can make your own -- but PLEASE MAKE SURE -# the directory exists and is writable; gitolite won't do that for you (unless -# it is the default, which is "$GL_ADMINDIR/logs") - -# $GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m-%d.log"; -# $GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y.log"; - -# -------------------------------------- - -# location of the performance log files - -# uncomment and set this variable if you want performance logging -# -# perf log files are different from access log files; they store different -# information, are not meant to be as long-lived, and so on - -# $GL_PERFLOGT="$GL_ADMINDIR/logs/perf-gitolite-%y-%m.log"; - -# -------------------------------------- - -# Please DO NOT change these three paths - $GL_CONF="$GL_ADMINDIR/conf/gitolite.conf"; $GL_KEYDIR="$GL_ADMINDIR/keydir"; $GL_CONF_COMPILED="$GL_ADMINDIR/conf/gitolite.conf-compiled.pm"; +# DO NOT CHANGE THE NEXT TWO LINES UNLESS YOU REALLY KNOW WHAT YOU'RE DOING. +# These variables are set automatically by the install method you choose. +# $GL_PACKAGE_CONF = ""; +# $GL_PACKAGE_HOOKS = ""; -# -------------------------------------- - -# if git on your server is on a standard path (that is -# ssh git@server git --version -# works), leave this setting as is. Otherwise, choose one of the -# alternatives, or write your own - -$GIT_PATH=""; -# $GIT_PATH="/opt/bin/"; - -# -------------------------------------- - -# ---------------------------------------------------------------------- -# BIG CONFIG SETTINGS - -# Please read doc/big-config.mkd for details +# ------------------------------------------------------------------------------ +# most often used/changed variables +# ------------------------------------------------------------------------------ +$GL_WILDREPOS = 0; +$PROJECTS_LIST = $ENV{HOME} . "/projects.list"; +$REPO_UMASK = 0077; +# ------------------------------------------------------------------------------ +# variables with an efficiency impact +# ------------------------------------------------------------------------------ $GL_BIG_CONFIG = 0; $GL_NO_DAEMON_NO_GITWEB = 0; -$GL_NO_CREATE_REPOS = 0; -$GL_NO_SETUP_AUTHKEYS = 0; - -# ---------------------------------------------------------------------- -# SECURITY SENSITIVE SETTINGS -# -# Settings below this point may have security implications. That -# usually means that I have not thought hard enough about all the -# possible ways to crack security if these settings are enabled. - -# Please see details on each setting for specifics, if any. -# ---------------------------------------------------------------------- - # Define which metadata variables shall be exported to the gitolite environment. # Those variables can be used in hooks, e.g. for cia.vc # A pubkey file might contain one or more of those variable. # They can be defined by e.g:"# git-username: idl0r" # Each '-' (dash) will be replaced by an '_' (underscore). -@GL_METADATA = ( "git-username", "git-email", "git-realname", "git-realname-ascii", "cia-vc-username" ); -@GL_METADATA_REQUIRED = ( "git-username", "git-email", "git-realname" ); - -# -------------------------------------- -# ALLOW REPO ADMIN TO SET GITCONFIG KEYS -# -# Gitolite allows you to set git repo options using the "config" keyword; see -# conf/example.conf for details and syntax. -# -# However, if you are in an installation where the repo admin does not (and -# should not) have shell access to the server, then allowing him to set -# arbitrary repo config options *may* be a security risk -- some config -# settings may allow executing arbitrary commands. -# -# You have 3 choices. By default $GL_GITCONFIG_KEYS is left empty, which -# completely disables this feature (meaning you cannot set git configs from -# the repo config). - +#@GL_METADATA = ( "git-username", "git-email", "git-realname", "git-realname-ascii", "cia-vc-username" ); +#@GL_METADATA_REQUIRED = ( "git-username", "git-email", "git-realname" ); + +# ------------------------------------------------------------------------------ +# VARIABLES WITH A SECURITY IMPACT. READ DOC WELL BEFORE CHANGING THESE. +# http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd#_variables_with_a_security_impact +# ------------------------------------------------------------------------------ +# $GL_ALL_READ_ALL = 0; +$GIT_PATH=""; $GL_GITCONFIG_KEYS = ""; - -# The second choice is to give it a space separated list of settings you -# consider safe. (These are actually treated as a set of regular expression -# patterns, and any one of them must match). For example: -# $GL_GITCONFIG_KEYS = "core\.logAllRefUpdates core\..*compression"; -# allows repo admins to set one of those 3 config keys (yes, that second -# pattern matches two settings from "man git-config", if you look) -# -# The third choice (which you may have guessed already if you're familiar with -# regular expressions) is to allow anything and everything: -# $GL_GITCONFIG_KEYS = ".*"; - -# NOTE that due to some quoting and interpolation issues I have not been able -# to look at, a literal "." needs to be specified in this string as \\. (two -# backslashes and a dot). So this is how you'd allow any keys in the "foo" -# category: -# $GL_GITCONFIG_KEYS = "foo\\..*"; - -# -------------------------------------- -# ALLOW GITCONFIG KEYS EVEN FOR WILD REPOS -# -# This is an efficiency issue more than a security issue, since this requires -# trawling through all of $REPO_BASE looking for stuff :) - # $GL_GITCONFIG_WILD = 0; - -# -------------------------------------- -# EXTERNAL COMMAND HELPER -- HTPASSWD - -# security note: runs an external command (htpasswd) with specific arguments, -# including a user-chosen "password". - -# if you want to enable the "htpasswd" command, give this the absolute path to -# whatever file apache (etc) expect to find the passwords in. - +$GL_NO_CREATE_REPOS = 0; +$GL_NO_SETUP_AUTHKEYS = 0; +# $GL_WILDREPOS_DEFPERMS = 'R @all'; $HTPASSWD_FILE = ""; - -# Look in doc/3 ("easier to link gitweb authorisation with gitolite" section) -# for more details on using this feature. - -# -------------------------------------- -# EXTERNAL COMMAND HELPER -- RSYNC - -# security note: runs an external command (rsync) with specific arguments, all -# presumably filled in correctly by the client-side rsync. - -# base path of all the files that are accessible via rsync. Must be an -# absolute path. Leave it undefined or set to the empty string to disable the -# rsync helper. - $RSYNC_BASE = ""; - -# $RSYNC_BASE = "/home/git/up-down"; -# $RSYNC_BASE = "/tmp/up-down"; - -# -------------------------------------- -# EXTERNAL COMMAND HELPER -- SVNSERVE - -# security note: runs an external command (svnserve) with specific arguments, -# as specified below. %u is substituted with the username. - -# This setting allows launching svnserve when requested by the ssh client. -# This allows using the same SSH setup (hostname/username/public key) for both -# SVN and git access. Leave it undefined or set to the empty string to disable -# svnserve access. - $SVNSERVE = ""; -# $SVNSERVE = "/usr/bin/svnserve -r /var/svn/ -t --tunnel-user=%u"; - -# -------------------------------------- -# ALLOW REPO CONFIG TO USE WILDCARDS - -# security note: this used to in a separate "wildrepos" branch. You can -# create repositories based on wild cards, give "ownership" to the specific -# user who created it, allow him/her to hand out R and RW permissions to other -# users to collaborate, etc. This is powerful stuff, and I've made it as -# secure as I can, but it hasn't had the kind of rigorous line-by-line -# analysis that the old "master" branch had. - -# This has now been rolled into master, with all the functionality gated by -# this variable. Set this to 1 if you want to enable the wildrepos features. -# Please see doc/wildcard-repositories.mkd for details. - -$GL_WILDREPOS = 0; - -# -------------------------------------- -# DEFAULT WILDCARD PERMISSIONS - -# If set, this value will be used as the default user-level permission rule of -# new wildcard repositories. The user can change this value with the setperms command -# as desired after repository creation; it is only a default. Note that @all can be -# used here but is special; no other groups can be used in user-level permissions. - -# $GL_WILDREPOS_DEFPERMS = 'R @all'; - -# -------------------------------------- -# WILDREPOS PERMS CATEGORIES - -# Originally, we only allowed "R" and "RW" in the setperms command. Now we -# allow the admin to define other categories as she wishes (example: MANAGERS, -# TESTERS, etc). - -# This variable is a space-sep list of the allowed categories. - -# PLEASE, *PLEASE*, read the section in doc/wildcard-repositories.mkd for -# caveats and warnings. This is a VERY powerful feature and if you're not -# careful you could mess up the ACLs nicely. - -# this is the internal default if you don't set it (like if you didn't update -# your ~/.gitolite.rc with new variables when you upgraded gitolite): -$GL_WILDREPOS_PERM_CATS = "READERS WRITERS"; - -# you can use your own categories in addition to the standard ones; I suggest -# you include READERS and WRITERS for backward compat though: -# $GL_WILDREPOS_PERM_CATS = "READERS WRITERS MANAGERS"; -# $GL_WILDREPOS_PERM_CATS = "READERS WRITERS MANAGERS TESTERS"; - -# -------------------------------------- -# HOOK CHAINING - -# by default, the update hook in every repo chains to "update.secondary". -# Similarly, the post-update hook in the admin repo chains to -# "post-update.secondary". If you're fine with the defaults, there's no need -# to do anything here. However, if you want to use different names or paths, -# change these variables - # $UPDATE_CHAINS_TO = "hooks/update.secondary"; # $ADMIN_POST_UPDATE_CHAINS_TO = "hooks/post-update.secondary"; - -# -------------------------------------- -# ADMIN DEFINED COMMANDS - -# WARNING: Use this feature only if (a) you really really know what you're -# doing or (b) you really don't care too much about security. Please read -# doc/admin-defined-commands.mkd for details. - # $GL_ADC_PATH = ""; +# $GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups" -# -------------------------------------- -# SITE-SPECIFIC INFORMATION - -# Some installations would like to give their users customised information -# (like a link to their own websites, for example) so that each end user does -# not have to grok all the gitolite documentation. - -# If this variable is defined, the "info" command will print it at the end of -# the listing. +# ------------------------------------------------------------------------------ +# less used/changed variables +# ------------------------------------------------------------------------------ +# $GL_ALL_INCLUDES_SPECIAL = 0; +# $GL_SLAVE_MODE = 0; +# $ENV{GL_SLAVES} = 'gitolite@server2 gitolite@server3'; +# PLEASE USE SINGLE QUOTES ABOVE, NOT DOUBLE QUOTES +$GL_WILDREPOS_PERM_CATS = "READERS WRITERS"; -# $GL_SITE_INFO = ""; +# ------------------------------------------------------------------------------ +# rarely changed variables +# ------------------------------------------------------------------------------ +$GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m.log"; +# $GL_PERFLOGT="$GL_ADMINDIR/logs/perf-gitolite-%y-%m.log"; # $GL_SITE_INFO = "XYZ.COM DEVELOPERS: PLEASE SEE http://xyz.com/gitolite/help first"; -# -------------------------------------- -# USERGROUP HANDLING - -# Some sites would like to store group membership outside gitolite, because -# they already have it in (usually) their LDAP server, and it doesn't make -# sense to be forced to duplicate this information. - -# Set the following variable to the name of a script that, given a username as -# argument, will return a list of groups that she is a member of. - -# $GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups" +# ------------------------------------------------------------------------------ +# variables that should NOT be changed after the install step completes +# ------------------------------------------------------------------------------ +$REPO_BASE="repositories"; -# -------------------------------------- +# ------------------------------------------------------------------------------ # per perl rules, this should be the last line in such a file: 1; diff --git a/contrib/adc/get-rights-and-owner.in-perl b/contrib/adc/get-rights-and-owner.in-perl new file mode 100755 index 0000000..d848cfb --- /dev/null +++ b/contrib/adc/get-rights-and-owner.in-perl @@ -0,0 +1,41 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +unshift @INC, $ENV{GL_BINDIR}; +require gitolite or die "parse gitolite.pm failed\n"; + +# get the repo name +my $repo = shift; +$repo =~ s/\.git$//; +# IMPORTANT NOTE: to do any of this inside a hook, you should just use +# $ENV{GL_REPO}, since it's guaranteed to be set to the right value + + + +# to do a "level 1" check (repo level -- not branch level), do this: +my ($perm, $creator) = &check_access($repo); +# you can pass in any repo name you wish instead of the active repo + +# the first return value looks like one of these, so you can just check for +# the presence of "R" or "W" and be done: +# _____R___W_ +# _____R_____ +# ___________ + +# The second value is "<gitolite>" for a normal repo, an actual username for +# a wildrepo, or "<notfound>" for a non-existent repo. + + + +# to do a "level 2" check (branches), do something like this +my $ret = &check_access($repo, 'refs/heads/foo', 'W', 1); +# the 2nd argument must be a *full* refname (i.e., not "master", but +# "refs/heads/master"). The 3rd argument is one of W, +, C, or D. The 4th +# argument should be any non-false perl value, like 1. + +# the return value may look like this: +# refs/.* +# or perhaps this, if you were denied +# DENIED by fallthru diff --git a/contrib/ldap/README.mkd b/contrib/ldap/README.mkd new file mode 100644 index 0000000..a7dc764 --- /dev/null +++ b/contrib/ldap/README.mkd @@ -0,0 +1,18 @@ +These programs were contributed by the Nokia MeeGo folks. + +The first 2 are perl and shell verisions of programs meant to be used as +`$GL_GET_MEMBERSHIPS_PGM` (see [this][ldap] for more). + + + * ldap-query-example.pl + * ldap-query-example.sh + +The third program is meant to be installed as an adc (admin-defined command, +see [here][adc]), and helps users change their LDAP passwords. + + * passwd + +Enjoy! + +[ldap]: http://github.com/sitaramc/gitolite/blob/pu/doc/big-config.mkd#_storing_usergroup_information_outside_gitolite_like_in_LDAP_ +[adc]: http://github.com/sitaramc/gitolite/blob/pu/doc/admin-defined-commands.mkd diff --git a/contrib/ldap/ldap-query-example.pl b/contrib/ldap/ldap-query-example.pl new file mode 100644 index 0000000..663e318 --- /dev/null +++ b/contrib/ldap/ldap-query-example.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl +# +# Copyright (c) 2010 Nokia Corporation +# +# This code is licensed to you under MIT-style license. License text for that +# MIT-style license is as follows: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ldap-query.pl <arg1> +# +# this script is used to perform ldap querys by giving one argument: +# - <arg1> the user UID for ldap search query +# +# NOTICE: This script requires libnet-ldap-perl package to be installed +# to the system. +# + +use Net::LDAP; + +# Script requires user UID as the only parameter +if ( $ARGV[0] eq '' || $ARGV[1] ne '' ) +{ + print "ldap-query.pl requires one argument, user's uid\n"; + exit 1; +} +$user = $ARGV[0]; + +# Create communication structure for LDAP connection +$ldap = Net::LDAP->new( + 'localhost', + port => 389, + debug => 0, + timeout => 120, + version => 3 ) or die "$@"; + +# Bind to LDAP with proper user +$ldapret = $ldap->bind( 'cn=administrator,o=company', + password => '5ecretpa55w0rd' ); +die "$ldapret->code" if $ldapret->code; + +# Create filter for LDAP query +my $filter = '(&'. + '(objectClass=groupAttributeObjectClassName)'. + "(uid=$user)". + ')'; + +# Execute the actual LDAP search to get groups for the given UID +$ldapret = $ldap->search( base => 'ou=users,ou=department,o=company', + scope => 'subtree', + filter => $filter ); + +# Parse search result to get actual group names +my $default_group = ''; +my $extra_groups = ''; + +foreach my $entry ( $ldapret->entries ) { + + $default_group = $entry->get_value( 'defaultGroupAttributeName' ) . ' ' . "$default_group"; + $extra_groups = $entry->get_value( 'extraGroupsAttributeName' ) . ' ' . "$extra_groups"; +} + +# Return group names for given user UID +print "$default_group" . "$extra_groups"; diff --git a/contrib/ldap/ldap-query-example.sh b/contrib/ldap/ldap-query-example.sh new file mode 100644 index 0000000..43d13e4 --- /dev/null +++ b/contrib/ldap/ldap-query-example.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# +# Copyright (c) 2010 Nokia Corporation +# +# This code is licensed to you under MIT-style license. License text for that +# MIT-style license is as follows: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ldap-query.sh <arg1> +# +# this script is used to perform ldap querys by giving one argument: +# - <arg1> the user UID for ldap search query +# +# NOTICE: This script requires ldap-utils and sed to be installed to the system. +# + +# Script requires user UID as the only parameter +# +if [ $# -ne 1 ] +then + echo "ldap-query.sh requires one argument, user's uid" + exit 1 +fi +uid_param="${1}" + +# Set needed LDAP search tool options for the query +ldap_host="localhost" +ldap_binddn="cn=administrator,o=company" +ldap_bindpw="5ecretpa55w0rd" +ldap_searchbase="ou=users,ou=department,o=company" +ldap_scope="subtree" + +# Construct the command line base with needed options for the LDAP query +ldap_options="-h ${ldap_host} -x -D ${ldap_binddn} -w ${ldap_bindpw} -b ${ldap_searchbase} -s ${ldap_scope}" + +# Construct the search filter for the LDAP query for the given UID +ldap_filter="(&(objectClass=groupAttributeObjectClassName)(uid=${uid_param}))" + +# Construct return attribute list for LDAP query result +attr1="defaultGroupAttributeName" +attr2="extraGroupsAttributeName" +ldap_attr="${attr1} ${attr2}" + +# Execute the actual LDAP search to get groups for the given UID +ldap_result=$(ldapsearch ${ldap_options} -LLL ${ldap_filter} ${ldap_attr}) + +# Edit search result to get space separated list of group names +ldap_result=$(echo ${ldap_result} | sed -e "s/.* ${attr1}://" -e "s/ ${attr2}://") + +# Return group names for given user UID +echo ${ldap_result} diff --git a/contrib/ldap/passwd b/contrib/ldap/passwd new file mode 100644 index 0000000..f555f65 --- /dev/null +++ b/contrib/ldap/passwd @@ -0,0 +1,112 @@ +#!/usr/bin/perl
+
+use Net::LDAP;
+use Term::ReadPassword;
+use Digest::SHA1;
+use MIME::Base64;
+use Data::UUID;
+use Crypt::Cracklib;
+
+my $PASSWD_MIN_LEN = 8;
+my $password;
+
+# parse RC file
+# $ENV{GL_RC} = "/home/gitolite/.gitolite.rc";
+die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
+
+# These come from .gitolite.rc file
+our ($GL_LDAP_HOST, $GL_LDAP_BIND_DN, $GL_LDAP_BIND_PASSWORD, $GL_LDAP_USER_DN);
+
+$Term::ReadPassword::ALLOW_STDIN = 1;
+
+# NOTICE: For some reason Perl fails to disable terminal echo
+# so following warning about ECHO must be given to the user
+
+# Warn about password echo because of bugs in Perl ReadPasword
+print "\nNOTE THAT THE PASSWORD WILL BE ECHOED TO THE SCREEN!\n" .
+"Please make sure no one is shoulder-surfing, and make sure\n" .
+"you clear your screen and scrollback history after you are done\n" .
+"(or close your terminal session).\n\n";
+
+print "Please type in your new password at the prompt.\n\n" .
+"Following special keys are available while typing:\n" .
+" <BackSpace> key to remove the last character\n" .
+" <Ctrl-U> to remove all characters\n" .
+" <Ctrl-C> to terminate password change operation\n" .
+" <Enter> to end password typing\n";
+
+while ( 1 ) {
+
+ print "\n"; # Start reading with new line
+ $password = read_password("Enter new password: ", 0, 1);
+
+ # Check the validity of new password
+ if ( length( $password ) >= $PASSWD_MIN_LEN # require minimum length
+ && $password =~ /([\x20-\x7E])/ # require printable characters
+ && $password =~ /[a-z]/ # require lower case letter
+ && $password =~ /[A-Z]/ # require upper case letter
+ && $password =~ /[0-9]/ # require number
+ && check( $password ) ) # require other than dictionary words
+ {
+ # Re-enter new password to check possible typos
+ if ( $password ne read_password("Enter password again: ") ) {
+
+ print "Passwords do not match!\n";
+ redo;
+ } else {
+
+ last; # Password is valid and there are no typos, so break out
+ }
+ } else { # Given password is not valid
+
+ print "Password must contain at least $PASSWD_MIN_LEN characters and numbers,\n" .
+ "must have both upper and lower case characters,\n" .
+ "can have special characters like !,",#,...\n" .
+ "but cannot be any valid dictionary word.\n";
+ redo;
+ }
+}
+
+# Create hash from the password to be stored to the LDAP
+my $ctx = Digest::SHA1->new();
+my $ug = new Data::UUID;
+my $salt = $ug->create_b64();
+$ctx->add( $password );
+$ctx->add( $salt );
+$password = '{SSHA}' . encode_base64( $ctx->digest . $salt, '' );
+
+# Create communication structure for LDAP connection
+my $ldap = Net::LDAP->new( $GL_LDAP_HOST ) or die "$@";
+my $r = $ldap->start_tls( verify => 'none',
+ sslversion => 'tlsv1' );
+if ( $r->code ) {
+ print "Password handling failed with $r->code return code!\n";
+ log_it( "Password change, LDAP connection failed for $ENV{GL_USER}" );
+ exit 1;
+}
+
+# Bind to LDAP with proper user
+$r = $ldap->bind( $GL_LDAP_BIND_DN,
+ password => $GL_LDAP_BIND_PASSWORD );
+if ( $r->code ) {
+ print "Password update failed with $r->code return code!\n";
+ log_it( "Password change, LDAP bind failed for $ENV{GL_USER}" );
+ exit 1;
+}
+
+# Update new password to the LDAP
+$r = $ldap->modify( "uid=$ENV{GL_USER},
+ $GL_LDAP_USER_DN",
+ replace => { 'userPassword', $password } );
+
+if ( $r->code ) {
+ print "Password change failed!\n" .
+ "Please contact administrator to change password.\n";
+# log_it( "Password change, LDAP modify failed for $ENV{GL_USER}" );
+} else {
+ print "Password changed succesfully.\n";
+# log_it( "Password change, LDAP modify done for $ENV{GL_USER}" );
+}
+
+$r = $ldap->unbind();
+
diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 7062be0..9dde36b 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -2,6 +2,28 @@ Major changes to gitolite, master branch only, most recent first, no dates but the tags can help you position stuff approximately [NYD = not yet documented due to lack of time...] + - v1.5.9 + + - Nokia MeeGo team contributed ldap scripts + + - large configs should now be twice as fast (except when gl-perms exists) + due to my finding and eliminating a wasted parse_acl + + - major change: split the config file when in big-config mode + (includes a data format change) + + - GL_ALL_READ_ALL to make things much, (MUCH!) faster for sites where all + can read all repos (like Fedora) + + - rc file revamp -- was getting too big and unwieldy; now the documentation + is in a new file instead of inline + + - allow gitolite to be used even when users have real IDs (thus $HOME is not + valid to find the rc file); allow /etc/gitolite/gitolite.rc then + + - BIG one for adc writers -- full blown access checks (ref level) can be + done from an ADC now (though it has to be in perl, not shell)! + - allow full access checks from perl (shell can only do level 1 checks); useful in hooks or ADCs diff --git a/doc/big-config.mkd b/doc/big-config.mkd index 440288b..69b5e46 100644 --- a/doc/big-config.mkd +++ b/doc/big-config.mkd @@ -4,6 +4,8 @@ In this document: * <a href="#_when_why_do_we_need_it_">when/why do we need it?</a> * <a href="#_how_do_we_use_it_">how do we use it?</a> + * <a href="#_access_rules_for_groups">access rules for groups</a> + * <a href="#_access_rules_for_individual_repos_split_config_">access rules for individual repos (split config)</a> * <a href="#_other_optimisations">other optimisations</a> * <a href="#_disabling_various_defaults">disabling various defaults</a> * <a href="#_optimising_the_authkeys_file">optimising the authkeys file</a> @@ -18,10 +20,10 @@ In this document: ### when/why do we need it? A "big config" is anything that has a few thousand users and a few thousand -repos, organised into groups that are much smaller in number (like maybe a few -hundreds of repogroups and a few dozens of usergroups). +repos, resulting in a very large 'compiled' config file. -So let's say you have +To understand the problem, consider what happens if you have something like +this in your gitolite conf file: @wbr = lynx firefox @devs = alice bob @@ -30,15 +32,15 @@ So let's say you have RW+ next = @devs RW master = @devs -Gitolite internally translates this to +Without the 'big config' setting, gitolite internally translates this to: repo lynx firefox RW+ next = alice bob RW master = alice bob -Not just that -- it now generates the actual config rules once for each -user-repo-ref combination (there are 8 combinations above; the compiled config -file looks partly like this: +and then generates the actual config rules once for each user-repo-ref +combination (there are 8 combinations above); the compiled config file looks +somewhat like this: %repos = ( 'firefox' => { @@ -51,20 +53,28 @@ file looks partly like this: 'bob' => 1 }, 'alice' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 4, + 'refs/heads/master', + 'RW' + ] ], 'bob' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 1, + 'refs/heads/next', + 'RW+' + ], + [ + 5, + 'refs/heads/master', + 'RW' + ] ] }, 'lynx' => { @@ -77,54 +87,73 @@ file looks partly like this: 'bob' => 1 }, 'alice' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 2, + 'refs/heads/next', + 'RW+' + ], + [ + 6, + 'refs/heads/master', + 'RW' + ] ], 'bob' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 3, + 'refs/heads/next', + 'RW+' + ], + [ + 7, + 'refs/heads/master', + 'RW' + ] ] } ); Phew! -You can imagine what that does when you have 10,000 users and 10,000 repos. -Let's just say it's not pretty :) +Of course, the output is the same whether you used groups (like `@wbr` and +`@devs` in the example above) or listed the repos directly on the 'repo' +lines. + +Anyway, you can imagine what that does when you have 10,000 users and 10,000 +repos. Let's just say it's not pretty :) <a name="_how_do_we_use_it_"></a> ### how do we use it? -Now, if you had all those 10,000 users and repos explicitly listed (no -groups), then there is no help. But if, like the above example, you had -groups like we used above, there is hope. - Just set $GL_BIG_CONFIG = 1; in the `~/.gitolite.rc` file on the server (see next section for more -variables). When you do that, and push this configuration, the compiled file -looks like this: +variables). When you do that, and push this configuration, one of two things +happens. + +<a name="_access_rules_for_groups"></a> + +#### access rules for groups + +If you used group names in the 'repo' lines (as in `repo @wbr`), then the +compiled config looks like this: %repos = ( '@wbr' => { '@devs' => [ - { - 'refs/heads/next' => 'RW+' - }, - { - 'refs/heads/master' => 'RW' - } + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 1, + 'refs/heads/master', + 'RW' + ] ], 'R' => { '@devs' => 1 @@ -132,7 +161,7 @@ looks like this: 'W' => { '@devs' => 1 } - }, + } ); %groups = ( '@devs' => { @@ -148,6 +177,62 @@ looks like this: That's a lot smaller, and allows orders of magintude more repos and groups to be supported. +<a name="_access_rules_for_individual_repos_split_config_"></a> + +#### access rules for individual repos (split config) + +If, on the other hand, you had the repos listed individually, (as in `repo +lynx firefox`), then the main config file would now look like this: + + %repos = (); + %split_conf = ( + 'firefox' => 1, + 'lynx' => 1 + ); + +And each individual repo's configuration would go its own directory. For +instance, `~/repositories/lynx.git/gl-conf` would look like this: + + %one_repo = ( + 'lynx' => { + 'R' => { + 'alice' => 1, + 'bob' => 1 + }, + 'W' => { + 'alice' => 1, + 'bob' => 1 + }, + 'alice' => [ + [ + 0, + 'refs/heads/next', + 'RW+' + ], + [ + 4, + 'refs/heads/master', + 'RW' + ] + ], + 'bob' => [ + [ + 1, + 'refs/heads/next', + 'RW+' + ], + [ + 5, + 'refs/heads/master', + 'RW' + ] + ] + } + ); + +That does not reduce the overall size of the repo config (because you did not +group the repos), but the main repo config is now even smaller! + <a name="_other_optimisations"></a> ### other optimisations @@ -169,22 +254,18 @@ if you *do* have a large number of repositories, and do *not* use gitolite's support for gitweb or git-daemon access (see "[easier to specify gitweb description and gitweb/daemon access][gwd]" for details). This will save a lot of time when you push the gitolite-admin repo with changes. This variable -also control whether "git config" lines (such as `config hooks.emailprefix = +also controls whether "git config" lines (such as `config hooks.emailprefix = "[gitolite]"`) will be processed or not. -Setting this is relatively harmless to a normal installation, unlike the next -two variables :-) `GL_NO_CREATE_REPOS` and `GL_NO_SETUP_AUTHKEYS` are meant -for installations where some backend system already exists that does all the -actual repo creation, and all the authentication setup (ssh auth keys), -respectively. +You should be a lot more careful with `GL_NO_CREATE_REPOS` and +`GL_NO_SETUP_AUTHKEYS`. These are meant for installations where some backend +system already exists that does all the actual repo creation, (including +setting up the proper hooks -- very important for access control), and all the +authentication setup (ssh auth keys), respectively. Summary: Please **leave those two variables alone** unless you're initials are "JK" ;-) -Also note that using all 3 of the `GL_NO_*` variables will result in -*everything* after the config compile being skipped. In other words, gitolite -is being used **only** for its access control language. - <a name="_optimising_the_authkeys_file"></a> #### optimising the authkeys file @@ -228,15 +309,29 @@ this (note the clever date command that always gets you last months log file!) ### what are the downsides? -There is one minor issue. +There are some downsides. The first one applies in all cases: + + * If you use the delegation feature, you can no longer define or extend + @groups in a fragment, for security reasons. It will also not let you use + any group other than the @fragname itself (specifically, groups which + contained a subset of the allowed @fragname, which would work normally, do + not work now). + + (If you didn't understand all that, you're probably not using delegation, + so feel free to ignore it!) + +The following apply if individual ("split") conf files are written, which in +turn only happens if you used repo names instead of group names on the `repo` +lines: -If you use the delegation feature, you can no longer define or extend -@groups in a fragment, for security reasons. It will also not let you use any -group other than the @fragname itself (specifically, groups which contained a -subset of the allowed @fragname, which would work normally, do not work now). + * the compile (gitolite-admin push) is now slower, because it potentially + has to write a few thousand small files instead of one large one. Since + the compile should be relatively infrequent compared to developer access, + this is ok -- the main config file is parsed much faster now, so every hit + to the server will benefit. -(If you didn't understand all that, you're probably not using delegation, so -feel free to ignore it!) + * we can no longer distinguish 'repo not found on disk' from 'you dont have + access'. They both now look like 'you dont have access'. <a name="_storing_usergroup_information_outside_gitolite_like_in_LDAP_"></a> @@ -298,10 +393,10 @@ path to this program, set `$GL_BIG_CONFIG` to 1, and that will be that. ### implementation notes -To understand how big-config works, we'll first look at how it works without -this setting. Think back to the example at the top, and assume 'alice' is -accessing the 'lynx' repo. The various rights are governed by the following -hash elements: +To understand how big-config works (at least when you're using grouped repos), +we'll first look at how it works without this setting. Think back to the +example at the top, and assume 'alice' is accessing the 'lynx' repo. The +various rights are governed by the following hash elements: # for the first level checks $repos{'lynx'}{'R'}{'alice'} = 1 diff --git a/doc/delegation.mkd b/doc/delegation.mkd index 9fe4293..b450403 100644 --- a/doc/delegation.mkd +++ b/doc/delegation.mkd @@ -71,7 +71,7 @@ in charge of malware ;-) [abe]: http://en.wikipedia.org/wiki/Alice_and_Bob#List_of_characters -You do this by adding branches to the `gitolite-admin` repo: +You do this by adding files with specific names to the `gitolite-admin` repo: # the admin repo access was probably like this to start with: repo gitolite-admin diff --git a/doc/gitolite.rc.mkd b/doc/gitolite.rc.mkd new file mode 100644 index 0000000..e354ff0 --- /dev/null +++ b/doc/gitolite.rc.mkd @@ -0,0 +1,332 @@ +# configuration variables for gitolite + +This is the documentation for the contents of the "rc" file +(`$HOME/.gitolite.rc`) on the server. Until now this documentation was +inline, within the rc file itself, but it has grown too large, too unwieldy, +and too difficult to grok for people new to gitolite. + +The documentation follows approximately the same order as the sample variables +in the (now reorganised) example "rc" file. + +In this document: + + * <a href="#_variables_that_should_not_be_touched_at_all">variables that should not be touched at all</a> + * <a href="#_most_often_used_changed_variables">most often used/changed variables</a> + * <a href="#_variables_with_an_efficiency_impact">variables with an efficiency impact</a> + * <a href="#_variables_with_a_security_impact">variables with a security impact</a> + * <a href="#_less_used_changed_variables">less used/changed variables</a> + * <a href="#_rarely_changed_variables">rarely changed variables</a> + +[Note: in perl, there is no actual boolean. The undefined value, the number +'0', and the empty string, are all 'false'. Everything else is 'true'. It is +thus common to use just 0/1 for false/true]. + +<a name="_variables_that_should_not_be_touched_at_all"></a> + +### variables that should not be touched at all + +The first section does not need too much elaboration. Let's just say bad +things happen if you change them. + +<a name="_most_often_used_changed_variables"></a> + +### most often used/changed variables + + * `$GL_WILDREPOS`, boolean, default 0 + + Setting this variable lets your users create repositories based on wild + cards, hand out R and RW permissions to other users to collaborate, etc. + + See [doc/wildcard-repositories.mkd][wild] for lots of info on this. + + * `$PROJECTS_LIST`, filename, default `~/projects.list` + + This is for gitweb users only. Gitweb setup has a variable called + `$projects_list` (please see gitweb docs for more on this). Set this to + the same value as that one. + + * `$REPO_UMASK`, octal, default `0077` + + The default UMASK that gitolite uses makes all the repos and their + contents have `rwx------` permissions. People who want to run gitweb + realise that this will not do. The correct way to deal with this is to + change this variable to `0027` (which gets you `rwxr-x---`), then add the + apache or httpd user running the webserver as a member of the 'gitolite' + group. + + Please note the syntax; the leading 0 is required. If you change it + *after* the install is complete, you'll have to do some chmod's also to + adjust permissions of files and directories that have already been + created. + +<a name="_variables_with_an_efficiency_impact"></a> + +### variables with an efficiency impact + + * `$GL_BIG_CONFIG`, boolean, default 0 + + This is the most common setting for efficiency in handling large repo/user + groups. This is a very powerful setting; please read + [doc/big-config.mkd][bc] for all the details you might need. + + There are 3 other settings related to big configs. They are changed only + in rare cases, however, so are described later. + + * `$GL_NO_DAEMON_NO_GITWEB`, boolean, default 0 + + If you have *lots* of repos, and you're *not* using gitweb or daemon, you + should probably set this on for efficiency. Despite the name, it also + blocks repo config settings. Please read [doc/big-config.mkd][bc] for + more details. + +<a name="_variables_with_a_security_impact"></a> + +### variables with a security impact + +**IMPORTANT NOTE** + +This section describes variables that, if not carefully used, can cause +security issues. It also includes variables which I personally do not use and +do not have the ability to test thoroughly + +Using non-default value for these variables voids the security reward in the +README. This does *not* mean they are less important or that I will ignore +problems; it just means *my* ability to catch problems may be limited by my +test suite, my actual production use, my time, and sometimes (LDAP comes to +mind) even my skill or resources available to me, and that therefore I depend +on feedback from my users to find or fix issues. + + * `$GL_ALL_READ_ALL`, boolean, default undef + + Eliminates the access control check for read access. Makes things much + (**much**!) faster when you have 10,000 projects and the compiled conf + file is more than 20MB in size! **Double check with your boss or have a + new job lined up before setting this on!** + + * `$GIT_PATH`, string, default empty + + If git on your server is on a standard path (that is `ssh git@server git + --version` works), leave this setting as is. Otherwise, find out where it + is and use that value here, for example `GIT_PATH="/opt/bin/";` + + * `$GL_GITCONFIG_KEYS`, string, default empty + + This setting allows the repo admin to define acceptable gitconfig keys. + + Gitolite allows you to set git repo options using the "config" keyword; + see conf/example.conf for details and syntax. + + However, if you are in an installation where the repo admin does not (and + should not) have shell access to the server, then allowing him to set + arbitrary repo config options *may* be a security risk -- some config + settings allow executing arbitrary commands! + + You have 3 choices. By default `$GL_GITCONFIG_KEYS` is left empty, which + completely disables this feature (meaning you cannot set git configs via + the repo config). + + The second choice is to give it a space separated list of settings you + consider safe. (These are actually treated as a set of perl regular + expression patterns, and any one of them must match). For example: + `$GL_GITCONFIG_KEYS = "core\\.logAllRefUpdates core\\..*compression";` + allows repo admins to set one of those 3 config keys (yes, that second + pattern matches two settings from "man git-config", if you look). + + The third choice (which you may have guessed already if you're familiar + with regular expressions) is to allow anything and everything: + `$GL_GITCONFIG_KEYS = ".*";` + + NOTE that due to some quoting and interpolation issues I have not been + able to look at, a literal "." needs to be specified in this string as + `\\.` (two backslashes and a dot). So this is how you'd allow any keys in + the "foo" category: `$GL_GITCONFIG_KEYS = "foo\\..*";` + + * `$GL_GITCONFIG_WILD`, boolean, default 0 + + This setting allows gitconfig keys even for wild repos. This is an + efficiency issue more than a security issue, since this requires trawling + through all of `$REPO_BASE` looking for stuff :) + + * `$GL_NO_CREATE_REPOS`, boolean, default 0 + + DO NOT CHANGE THIS unless you have other means to create repos and + correctly populate them with the required hooks. No hooks, no access + control; you have been warned! + + * `$GL_NO_SETUP_AUTHKEYS`, boolean, default 0 + + DO NOT CHANGE THIS unless you have other means to setup the authkeys file + (`~/.ssh/authorized_keys`). In an extreme case, if you switch this on + without also fixing up the authkeys file, users who you think you deleted + may still have access. All in all, please be careful, as with any change + that affects ssh. + + * `$GL_WILDREPOS_DEFPERMS`, string, default undef + + This sets default wildcard permissions for newly created wildcard repos. + + If set, this value will be used as the default user-level permission rule + of new wildcard repositories. The user can change this value with the + setperms command as desired after repository creation; it is only a + default. + + Example: `$GL_WILDREPOS_DEFPERMS = 'R @all';` + + * `$HTPASSWD_FILE`, string, default empty + + Gitolite can help users run the htpasswd command in a secure manner (since + gitolite has already identified them by an ssh key). If you want to + enable this, give the variable the absolute path to whatever file apache + (etc) expect to find the passwords in. + + Look in [doc/3-faq-tips-etc.mkd][faq] ("easier to link gitweb + authorisation with gitolite" section) for more details on using this + feature. + + * `$RSYNC_BASE`, string, default empty + + Gitolite can be used to allow fine grained control of the rsync command. + + This setting enables the rsync external command helper, by specifying the + base path of all the files that are accessible via rsync. It must be an + absolute path, like `$RSYNC_BASE = "/home/git/up-down";`. Leave it + undefined or set to the empty string to disable the rsync helper. + + When enabled, it runs rsync with specific arguments, all presumably filled + in correctly by the client-side rsync. However, I am not an expert on how + rsync may be abused, so if it breaks, you get to keep both pieces! + + * `$SVNSERVE`, string, default empty + + Gitolite can also be used to gate access (though not at a fine grained + level) to SVN if needed, passing authentication information on to + `svnserve`. This setting allows launching svnserve when requested by the + ssh client. This allows using the same SSH setup for both SVN and git + access. Leave it undefined or set to the empty string to disable svnserve + access. + + The setting will look something like (where the %u is substituted with the + username): + + $SVNSERVE = "/usr/bin/svnserve -r /var/svn/ -t --tunnel-user=%u"; + + * hook chaining + + * `$UPDATE_CHAINS_TO`, string, default "hooks/update.secondary" + * `$ADMIN_POST_UPDATE_CHAINS_TO`, string, default + "hooks/post-update.secondary" + + By default, the update hook in every repo chains to "update.secondary". + Similarly, the post-update hook in the admin repo chains to + "post-update.secondary". If you're fine with the defaults, there's no + need to do anything here. However, if you want to use different names or + paths, change these variables. + + * `$GL_ADC_PATH`, string, default undef + + This setting enables admin defined commands. + + **WARNING**: Use this feature only if (a) you really know what you're + doing and (b) you really, **really**, know what you're doing! Please read + [doc/admin-defined-commands.mkd][adc] for details. This is an extremely + powerful and flexible feature, and naturally anything that flexible can be + a security risk! + + * `$GL_GET_MEMBERSHIPS_PGM`, string, default undef + + Some sites would like to store group membership outside gitolite, because + they already have it in (usually) their LDAP server, and it doesn't make + sense to be forced to duplicate this information. + + Set the following variable to the name of a script that, given a username + as argument, will return a list of groups that she is a member of. See + [doc/big-config.mkd][bc] for more details. + + Example: `$GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups"` + +<a name="_less_used_changed_variables"></a> + +### less used/changed variables + + * `$GL_ALL_INCLUDES_SPECIAL`, boolean, default undef + + Giving access to @all users (as in `R = @all`) in the config normally + does *not* include the special users "gitweb" and "daemon". If you want + @all to include these two users, set this variable. + + * mirroring setup + + These two variables enable mirroring support; see + [doc/mirroring.mkd][mirr] for details. The two variables are + `$GL_SLAVE_MODE`, (boolean, default undef), and `$ENV{GL_SLAVES}`, + (environment variable, string, default undef) + + Note on the second variable above: you must use single quotes to give it + its value, not double quotes, (like `$ENV{GL_SLAVES} = 'gitolite@server2 + gitolite@server3';`). Also note that this is an environment variable, not + a regular perl variable, so mind the syntax if you're not a perl guy :-) + + * `$GL_WILDREPOS_PERM_CATS`, string, default "READERS WRITERS" + + Originally, we only allowed "R" and "RW" in the setperms command. Now we + allow the admin to define other categories as she wishes (example: + MANAGERS, TESTERS, etc). + + This variable is a space-separated list of the allowed categories. + + PLEASE, *PLEASE*, read the section in + [doc/wildcard-repositories.mkd][wild] for caveats and warnings. This is a + VERY powerful feature and if you're not careful you could mess up the ACLs + nicely. + + This is the internal default if you don't set it (like if you didn't + update your ~/.gitolite.rc with new variables when you upgraded gitolite): + + $GL_WILDREPOS_PERM_CATS = "READERS WRITERS"; + + You can use your own categories in addition to the standard ones; I + suggest you include READERS and WRITERS for backward compatbility though: + + $GL_WILDREPOS_PERM_CATS = "READERS WRITERS MANAGERS TESTERS"; + +<a name="_rarely_changed_variables"></a> + +### rarely changed variables + + * `$GL_LOGT`, string, default `$GL_ADMINDIR/logs/gitolite-%y-%m.log` + + This is the template for location of the log files and format of their + names. + + The default produces files like `~/.gitolite/logs/gitolite-2009-09.log`. + If you make up your own templates, **PLEASE MAKE SURE** the directory + exists and is writable; gitolite won't do that for you unless it is the + default, ("$GL_ADMINDIR/logs") + + * `$GL_PERFLOGT`, string, default undef + + This gives the location of the performance log files. Uncomment and set + this variable if you want performance logging. Performance log files are + kept separate from access log files because they store different, usually + much shorter term, information. + + * `$GL_SITE_INFO`, string, default undef + + Some installations would like to give their users customised information + (like a link to their own websites, for example) so that users have a + quick way to find some links or information. + + If this variable is defined, the "info" command will print it at the end + of the listing. + + * `$REPO_BASE`, string, default "repositories" + + This is where all the repos go. If it's not an absolute path, it is + considered to be relative to $HOME. Changing it after the install has + completed is doable, but tricky if you don't know how gitolite works. + +[wild]: http://github.com/sitaramc/gitolite/blob/pu/doc/wildcard-repositories.mkd +[bc]: http://github.com/sitaramc/gitolite/blob/pu/doc/big-config.mkd +[faq]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd +[adc]: http://github.com/sitaramc/gitolite/blob/pu/doc/admin-defined-commands.mkd +[mirr]: http://github.com/sitaramc/gitolite/blob/pu/doc/mirroring.mkd diff --git a/doc/install-transcript.mkd b/doc/install-transcript.mkd index 1a3bcbc..178ba1a 100644 --- a/doc/install-transcript.mkd +++ b/doc/install-transcript.mkd @@ -127,7 +127,7 @@ described in the `ssh-copy-id` section in `doc/3-faq-tips-etc.mkd`). | .. | +-----------------+ - sita@sita-lt:~ $ ssh-copy-id -i ~/.ssh/id_rsa git@server + sita@sita-lt:~ $ ssh-copy-id -i ~/.ssh/id_rsa.pub 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: diff --git a/doc/overkill.mkd b/doc/overkill.mkd index bb85e89..c71ccd6 100644 --- a/doc/overkill.mkd +++ b/doc/overkill.mkd @@ -23,13 +23,9 @@ repos, you can use plain Unix permissions to get a lot of this done: git init --bare --shared reponame.git * For each user who needs access to the repos, add them as members to the - "git" group also. On Mandriva this is: + "git" group also. On Fedora this is: - usermod -G git username - - Don't forget that `-G` *replaces* the list of supplementary groups for the - user, so be sure to first check if he is already member of some groups and - keep those in the command (comma-separated). + usermod -a -G git username And that's basically it. The "init --shared" will create the repos with "chmod -R g+s". If you have existing repos where you forgot (or didn't know) diff --git a/doc/progit-article.mkd b/doc/progit-article.mkd index da016d3..2667c9b 100644 --- a/doc/progit-article.mkd +++ b/doc/progit-article.mkd @@ -24,7 +24,7 @@ We will describe this last method in this article; for the other methods please You start by obtaining public key based access to your server, so that you can log in from your workstation to the server without getting a password prompt. The following method works on Linux; for other workstation OSs you may have to do this manually. We assume you already had a key pair generated using `ssh-keygen`. - $ ssh-copy-id -i ~/.ssh/id_rsa gitolite@gitserver + $ ssh-copy-id -i ~/.ssh/id_rsa.pub gitolite@gitserver This will ask you for the password to the gitolite account, and then set up public key access. This is **essential** for the install script, so check to make sure you can run a command without getting a password prompt: diff --git a/doc/ssh-troubleshooting.mkd b/doc/ssh-troubleshooting.mkd index 6238cf9..0fa7169 100644 --- a/doc/ssh-troubleshooting.mkd +++ b/doc/ssh-troubleshooting.mkd @@ -307,7 +307,7 @@ from scratch: `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 + * run `ssh-copy-id -i ~/.ssh/id_rsa.pub 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. diff --git a/doc/who-uses-it.mkd b/doc/who-uses-it.mkd index f3ecb08..82871f3 100644 --- a/doc/who-uses-it.mkd +++ b/doc/who-uses-it.mkd @@ -50,3 +50,8 @@ users as well. [gentoo1]: http://archives.gentoo.org/gentoo-dev/msg_2812c9b9e768f64b46360ab17b9d0024.xml [gentoo2]: http://www.gentoo.org/proj/en/overlays/ + +**Nokia MeeGo** uses Gitolite internally, and has also contributed LDAP +specific code (see [contrib/ldap][ldap] directory for details). + +[ldap]: http://github.com/sitaramc/gitolite/blob/pu/contrib/ldap diff --git a/src/gitolite.pm b/src/gitolite.pm index 550cf1c..63f7612 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -46,9 +46,14 @@ our $ADC_CMD_ARGS_PATT=qr(^[0-9a-zA-Z._\@/+:-]*$); our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG, $GL_PERFLOGT, $PROJECTS_LIST, $GL_ALL_INCLUDES_SPECIAL, $GL_SITE_INFO, $GL_GET_MEMBERSHIPS_PGM, $GL_WILDREPOS_PERM_CATS, $GL_KEYDIR, @GL_METADATA, @GL_METADATA_REQUIRED); our %repos; our %groups; -our %repo_config; +our %git_configs; +our %split_conf;; our $data_version; -our $current_data_version = '1.6'; +our $current_data_version = '1.7'; + +# the following are read in from individual repo's gl-conf files, if present +our %one_repo; +our %one_git_config; # ---------------------------------------------------------------------------- # convenience subs @@ -154,21 +159,21 @@ sub check_ref { # permission must also match the action (W or +) being attempted. If none # of them match, the access is denied. - # Notice that the function DIES!!! Any future changes that require more - # work to be done *after* this, even on failure, can start using return - # codes etc., but for now we're happy to just die. + # Notice that the function DIES unless a non-false 5th argument is present - my ($allowed_refs, $repo, $ref, $perm) = @_; + my ($allowed_refs, $repo, $ref, $perm, $dry_run) = @_; my @allowed_refs = sort { $a->[0] <=> $b->[0] } @{$allowed_refs}; for my $ar (@allowed_refs) { my $refex = $ar->[1]; # refex? sure -- a regex to match a ref against :) next unless $ref =~ /^$refex/; + return "DENIED by $refex" if $ar->[2] eq '-' and $dry_run; die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->[2] eq '-'; # as far as *this* ref is concerned we're ok return $refex if ($ar->[2] =~ /\Q$perm/); } + return "DENIED by fallthru" if $dry_run; die "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru\n"; } @@ -183,33 +188,19 @@ sub ln_sf } } -# collect repo patterns for all %repos - -# for each repo passed (actual repos only please!), use either its own name if -# it exists as is in the repos hash, or find and use the pattern that matches - -sub collect_repo_patts +# list physical repos +sub list_phy_repos { - my $repos_p = shift; - my %repo_patts = (); + my @phy_repos; wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); for my $repo (`find . -type d -name "*.git"`) { chomp ($repo); $repo =~ s(\./(.*)\.git$)($1); - # the key has to be in the list, since the repo physically exists - # -- my($perm, $creator, $wild) = &repo_rights($repo); - # -- $repo_patts{$repo} = $wild || $repo; - # turns out we're not using the value anywhere, so no point wasting - # all those cycles getting all repos' rights, at least until a real - # use for it comes along. But when it does come along, remember that - # $wild is now a space separated list of matching patterns (or empty - # if no wild patterns matched $repo). It is NOT a single value - # anymore! - $repo_patts{$repo} = 1; + push @phy_repos, $repo; } - return %repo_patts; + return @phy_repos; } @@ -268,8 +259,15 @@ sub where_is_rc return if $ENV{GL_RC}; - my $glrc = $ENV{HOME} . "/.gitolite.rc"; - $ENV{GL_RC} = $glrc if (-f $glrc); + # Fedora doesn't actually have a "hosting user" at all (yeah -- bet you + # didn't know gitolite was *that* flexible!), so there's no fixed $HOME, + # and they prefer to keep their RC file in /etc/gitolite. + for my $glrc ( $ENV{HOME} . "/.gitolite.rc", "/etc/gitolite/gitolite.rc" ) { + if (-f $glrc) { + $ENV{GL_RC} = $glrc; + last; + } + } } # ---------------------------------------------------------------------------- @@ -312,16 +310,10 @@ sub new_repo # ---------------------------------------------------------------------------- { - # the following sub needs some persistent data, so we make a closure + # the following subs need some persistent data, so we make a closure my $cache_filled = 0; my %cached_groups; - - # "who created this repo", "am I on the R list", and "am I on the RW list"? - sub wild_repo_rights - { - # set default categories - $GL_WILDREPOS_PERM_CATS ||= "READERS WRITERS"; - my ($repo, $user) = @_; + sub fill_cache { # pull in basic group info unless ($cache_filled) { local(%repos, %groups); @@ -336,6 +328,15 @@ sub new_repo %cached_groups = %groups; $cache_filled++; } + } + + # "who created this repo", "am I on the R list", and "am I on the RW list"? + sub wild_repo_rights + { + # set default categories + $GL_WILDREPOS_PERM_CATS ||= "READERS WRITERS"; + my ($repo, $user) = @_; + # creator my $c = ''; if ( -f "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-creater") { @@ -364,6 +365,7 @@ sub new_repo # file). We replace each @foo with $user if $cached_groups{'@foo'}{$user} # exists (i.e., $user is a member of @foo) for my $g ($perms =~ /\s(\@\S+)/g) { + fill_cache(); # get %cached_groups $perms =~ s/ $g(?!\S)/ $user/ if $cached_groups{$g}{$user}; } # now setup the perm_cats hash to be returned @@ -449,14 +451,14 @@ sub get_set_desc # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# set/unset repo configs +# set/unset git configs # ---------------------------------------------------------------------------- -sub setup_repo_configs +sub setup_git_configs { - my ($repo, $repo_config_p) = @_; + my ($repo, $git_configs_p) = @_; - while ( my ($key, $value) = each(%{ $repo_config_p->{$repo} }) ) { + while ( my ($key, $value) = each(%{ $git_configs_p->{$repo} }) ) { if ($value) { $value =~ s/^"(.*)"$/$1/; system("git", "config", $key, $value); @@ -555,8 +557,6 @@ sub parse_acl %repos = %saved_repos; %groups = %saved_groups; } else { die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED; - $saved_crwu = "$creator,$perm_cats_sig,$gl_user"; - %saved_repos = %repos; %saved_groups = %groups; } unless (defined($data_version) and $data_version eq $current_data_version) { # this cannot happen for 'easy-install' cases, by the way... @@ -565,6 +565,9 @@ sub parse_acl die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED; } + $saved_crwu = "$creator,$perm_cats_sig,$gl_user"; + %saved_repos = %repos; %saved_groups = %groups; + add_repo_conf($repo) if $repo; # basic access reporting doesn't send $repo, and doesn't need to; you just # want the config dumped as is, really @@ -584,7 +587,7 @@ sub parse_acl $repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D}; $repos{$dr}{CREATE_IS_C} = 1 if $repos{$r}{CREATE_IS_C}; $repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS}; - $repo_config{$dr} = $repo_config{$r} if $repo_config{$r}; + $git_configs{$dr} = $git_configs{$r} if $git_configs{$r}; for my $u ('@all', "$gl_user - wild", @user_plus, keys %perm_cats) { my $du = $gl_user; $du = '@all' if $u eq '@all' or ($perm_cats{$u} || '') eq '@all'; @@ -603,6 +606,17 @@ sub parse_acl return ($wild); } +# add repo conf from repo.git/gl-conf +sub add_repo_conf +{ + my ($repo) = shift; + return unless $split_conf{$repo}; + do "$ENV{GL_REPO_BASE_ABS}/$repo.git/gl-conf" or return; + $repos{$repo} = $one_repo{$repo}; + $git_configs{$repo} = $one_git_config{$repo}; +} + + # ---------------------------------------------------------------------------- # print a report of $user's basic permissions # ---------------------------------------------------------------------------- @@ -639,6 +653,8 @@ sub report_basic local $ENV{GL_USER} = $user; &parse_acl($GL_CONF_COMPILED, "", "CREATOR"); + # all we need is for 'keys %repos' to come up with all the names, so: + @repos{ keys %split_conf } = values %split_conf if %split_conf; # send back some useful info if no command was given &report_version($GL_ADMINDIR, $user); @@ -773,10 +789,9 @@ sub expand_wild # helper/convenience routine to get rights and ownership from a shell command sub cli_repo_rights { - my ($perm, $creator, $wild) = &repo_rights($_[0]); - $perm =~ s/ /_/g; - $creator =~ s/^\(|\)$//g; - print "$perm $creator\n"; + # check_access does a lot more, so just call it. Since it returns perms + # and creator separately, just space-join them and print it. + print join(" ", &check_access($_[0])), "\n"; } sub can_read { @@ -1090,10 +1105,13 @@ sub get_memberships { sub check_access { - my ($GL_CONF_COMPILED, $repo, $path, $perm) = @_; - my $ref = "NAME/$path"; + my ($repo, $ref, $aa, $dry_run) = @_; + # aa = attempted access - &parse_acl($GL_CONF_COMPILED); + my ($perm, $creator, $wild) = &repo_rights($repo); + $perm =~ s/ /_/g; + $creator =~ s/^\(|\)$//g; + return ($perm, $creator) unless $ref; # until I do some major refactoring (which will bloat the update hook a # bit, sadly), this code duplicates stuff in the current update hook. @@ -1106,7 +1124,11 @@ sub check_access push @allowed_refs, @ { $repos{'@all'}{$ENV{GL_USER}} || [] }; push @allowed_refs, @ { $repos{$repo}{'@all'} || [] }; - &check_ref(\@allowed_refs, $repo, $ref, $perm); + if ($dry_run) { + return &check_ref(\@allowed_refs, $repo, $ref, $aa, $dry_run); + } else { + &check_ref(\@allowed_refs, $repo, $ref, $aa); + } } # ---------------------------------------------------------------------------- @@ -1136,7 +1158,7 @@ sub ext_cmd_rsync # ok now check if we're permitted to execute a $perm action on $path # (taken as a refex) using rsync. - &check_access($GL_CONF_COMPILED, 'EXTCMD/rsync', $path, $perm); + &check_access('EXTCMD/rsync', "NAME/$path", $perm); # that should "die" if there's a problem wrap_chdir($RSYNC_BASE); diff --git a/src/gl-auth-command b/src/gl-auth-command index e2ea9f5..2f32dc1 100755 --- a/src/gl-auth-command +++ b/src/gl-auth-command @@ -32,12 +32,13 @@ use warnings; # ---------------------------------------------------------------------------- # these are set by the "rc" file -our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS, $GL_WILDREPOS_DEFPERMS, $GL_ADC_PATH, $SVNSERVE, $PROJECTS_LIST, $GL_SLAVE_MODE, $GL_PERFLOGT, @GL_METADATA); +our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS, $GL_WILDREPOS_DEFPERMS, $GL_ADC_PATH, $SVNSERVE, $PROJECTS_LIST, $GL_SLAVE_MODE, $GL_PERFLOGT, $GL_ALL_READ_ALL, @GL_METADATA); # and these are set by gitolite.pm our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT, $ADC_CMD_ARGS_PATT); our %repos; our %groups; -our %repo_config; +our %git_configs; +our %split_conf;; # the common setup module is in the same directory as this running program is my $bindir = $0; @@ -227,14 +228,19 @@ $ENV{GL_REPO}=$repo; # first level permissions check # ---------------------------------------------------------------------------- -my ($perm, $creator, $wild) = &repo_rights($repo); +my ($perm, $creator, $wild); +if ( $GL_ALL_READ_ALL and $verb =~ $R_COMMANDS and -d "$ENV{GL_REPO_BASE_ABS}/$repo.git") { + $perm = 'R'; +} else { + ($perm, $creator, $wild) = &repo_rights($repo); +} if ($perm =~ /C/) { # it was missing, and you have create perms wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); new_repo($repo, "$GL_ADMINDIR/hooks/common", $user); # note pwd is now the bare "repo.git"; new_repo does that... wrap_print("gl-perms", "$GL_WILDREPOS_DEFPERMS\n") if $GL_WILDREPOS_DEFPERMS; - &setup_repo_configs($repo, \%repo_config); + &setup_git_configs($repo, \%git_configs); &setup_daemon_access($repo); &add_del_line ("$repo.git", $PROJECTS_LIST, &setup_gitweb_access($repo, '', '')); wrap_chdir($ENV{HOME}); diff --git a/src/gl-compile-conf b/src/gl-compile-conf index e962a9c..f8d35bb 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -92,6 +92,9 @@ our %groups = (); # in between :) my %repos = (); +# repos whose ACLs don't make it into the main compiled config file +my %split_conf = (); + # rule sequence number my $rule_seq = 0; @@ -105,8 +108,8 @@ our $current_data_version; # this comes from gitolite.pm # catch usernames<->pubkeys mismatches; search for "lint" below my %user_list = (); -# repo configurations -our %repo_config = (); +# repo specific 'git config' stuff +our %git_configs = (); # gitweb descriptions and owners; plain text, keyed by "$repo.git" my %desc = (); @@ -274,7 +277,7 @@ sub parse_conf_line } } } - # configuration + # repo specific 'git config' stuff elsif ($line =~ /^config (.+) = ?(.*)/) { my ($key, $value) = ($1, $2); @@ -283,7 +286,7 @@ sub parse_conf_line die "$ABRT git config $key not allowed\ncheck GL_GITCONFIG_KEYS in the rc file for how to allow it\n" if (@matched < 1); for my $repo (@{ $repos_p }) # each repo in the current stanza { - $repo_config{$repo}{$key} = $value; + $git_configs{$repo}{$key} = $value; # no problem if it's a plain repo (non-pattern, non-groupname) # OR wild configs are allowed unless ( ($repo =~ $REPONAME_PATT and $repo !~ /^@/) or $GL_GITCONFIG_WILD) { @@ -405,26 +408,31 @@ for my $fragment_file (glob("conf/fragments/*.conf")) parse_conf_file($fragment_file, $fragment); } -my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" ); -my $data_version = $current_data_version; -print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]); -my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]); -$dumped_data .= Data::Dumper->Dump([\%repo_config], [qw(*repo_config)]) if %repo_config; -# the dump uses single quotes, but we convert any strings containing $creator -# and $gl_user to double quoted strings. A bit sneaky, but not too much... -$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; -print $compiled_fh $dumped_data; -if (%groups) { - $dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]); - $dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g; +sub write_compiled_conf +{ + my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" ); + my $data_version = $current_data_version; + print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]); + my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]); + $dumped_data .= Data::Dumper->Dump([\%git_configs], [qw(*git_configs)]) if %git_configs; + # the dump uses single quotes, but we convert any strings containing $creator + # and $gl_user to double quoted strings. A bit sneaky, but not too much... $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; print $compiled_fh $dumped_data; + if (%groups) { + $dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]); + $dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g; + $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; + print $compiled_fh $dumped_data; + } + print $compiled_fh Data::Dumper->Dump([\%split_conf], [qw(*split_conf)]) if %split_conf; + close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n"; + rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED"; } -close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n"; -rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED"; # ---------------------------------------------------------------------------- -# (that ends the config file compiler and write) +# (that ends the config file compiler, though we postpone the writing +# for now to deal with the latest GL_BIG_CONFIG innovation!) # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- @@ -450,25 +458,31 @@ die "\n\t\t***** AAARGH! *****\n" . "\tthe newer features, please upgrade.\n" if $git_version < 10602; # that's 1.6.2 to you - - -# ---------------------------------------------------------------------------- -# the rest of this program can be "switched off"; see doc/big-config.mkd for -# details. -# ---------------------------------------------------------------------------- - # ---------------------------------------------------------------------------- -# any new repos to be created? +# most of the rest of this program can be "switched off"; see +# doc/big-config.mkd for details. # ---------------------------------------------------------------------------- -# repo-base needs to be an absolute path for this loop to work right +# repo-base needs to be an absolute path due to all the jumping around we do, # so if it was not already absolute, prefix $HOME. $ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" ); -unless ($GL_NO_CREATE_REPOS) { +# process the normal repos in %repos. This includes creating them if needed +# (and GL_NO_CREATE_REPOS is not set), checking hooks, and finally, if +# GL_BIG_CONFIG is set, writing out the one-repo config file for directly +# specified repos (i.e., "repo foo", not "@grp = foo" + "repo @grp") +do_normal_repos(); +write_compiled_conf(); # write out the final compiled config + +# ---------------------------------------------------------------------------- +# process the normal repos in %repos (create, hook, one_repo config...) +# ---------------------------------------------------------------------------- + +sub do_normal_repos +{ wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); - # autocreate repos. Start with the ones that are normal repos in %repos + # start with the ones that are normal repos in %repos my @repos = grep { $_ =~ $REPONAME_PATT and not /^@/ } sort keys %repos; # then, for each repogroup, find the members of the group and add them in map { push @repos, keys %{ $groups{$_} } } grep { /^@/ } keys %repos; @@ -477,39 +491,67 @@ unless ($GL_NO_CREATE_REPOS) { @repos = sort keys %seen; for my $repo (sort @repos) { - next unless $repo =~ $REPONAME_PATT; - next if $repo =~ m(^\@|EXTCMD/); # these are not real repos - unless (-d "$repo.git") { - print STDERR "creating $repo...\n"; - new_repo($repo, "$GL_ADMINDIR/hooks/common"); - # new_repo would have chdir'd us away; come back - wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); - } + next unless $repo =~ $REPONAME_PATT; # skip repo patterns + next if $repo =~ m(^\@|EXTCMD/); # skip groups and fake repos + + unless ($GL_NO_CREATE_REPOS) { + unless (-d "$repo.git") { + print STDERR "creating $repo...\n"; + new_repo($repo, "$GL_ADMINDIR/hooks/common"); + # new_repo would have chdir'd us away; come back + wrap_chdir("$ENV{GL_REPO_BASE_ABS}"); + } - # when repos are copied over from elsewhere, one had to run easy install - # once again to make the new (OS-copied) repo contain the proper update - # hook. Perhaps we can make this easier now, and eliminate the easy - # install, with a quick check (and a new, empty, "hook" as a sentinel) - unless (-l "$repo.git/hooks/gitolite-hooked") { - ln_sf("$GL_ADMINDIR/hooks/common", "*", "$repo.git/hooks"); - # in case of package install, GL_ADMINDIR is no longer the top cop; - # override with the package hooks - ln_sf("$GL_PACKAGE_HOOKS/common", "*", "$repo.git/hooks") if $GL_PACKAGE_HOOKS; + # when repos are copied over from elsewhere, one had to run easy install + # once again to make the new (OS-copied) repo contain the proper update + # hook. Perhaps we can make this easier now, and eliminate the easy + # install, with a quick check (and a new, empty, "hook" as a sentinel) + unless (-l "$repo.git/hooks/gitolite-hooked") { + ln_sf("$GL_ADMINDIR/hooks/common", "*", "$repo.git/hooks"); + # in case of package install, GL_ADMINDIR is no longer the top cop; + # override with the package hooks + ln_sf("$GL_PACKAGE_HOOKS/common", "*", "$repo.git/hooks") if $GL_PACKAGE_HOOKS; + } } + + # write a one_repo config for normal repos declared directly (not just via a group) + write_1_compiled_conf($repo) if $GL_BIG_CONFIG and $repos{$repo} and -d "$repo.git"; } } -# ---------------------------------------------------------------------------- -# collect repo_patt for each actual repo -# ---------------------------------------------------------------------------- +sub write_1_compiled_conf +{ + # warning: writes and *deletes* it from %repos and %git_configs + my ($repo) = shift; + my (%one_repo, %one_git_config); -# go through each actual repo on disk, and match it to either its own name in -# the config (non-wild) or a wild pattern that matches it. Lots of things -# later will need this correspondence so we may as well snarf it in one shot + open(my $compiled_fh, ">", "$repo.git/gl-conf") or return; + $one_repo{$repo} = $repos{$repo}; + delete $repos{$repo}; + my $dumped_data = Data::Dumper->Dump([\%one_repo], [qw(*one_repo)]); -my %repo_patts = (); -%repo_patts = &collect_repo_patts(\%repos) unless $GL_NO_DAEMON_NO_GITWEB; + if ($git_configs{$repo}) { + $one_git_config{$repo} = $git_configs{$repo}; + delete $git_configs{$repo}; + $dumped_data .= Data::Dumper->Dump([\%one_git_config], [qw(*one_git_config)]); + } + + # the dump uses single quotes, but we convert any strings containing $creator + # and $gl_user to double quoted strings. A bit sneaky, but not too much... + $dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g; + print $compiled_fh $dumped_data; + close $compiled_fh; + + $split_conf{$repo} = 1; +} + +# ---------------------------------------------------------------------------- +# get a list of physical repos for later +# ---------------------------------------------------------------------------- + +my @phy_repos = (); +@phy_repos = &list_phy_repos() unless $GL_NO_DAEMON_NO_GITWEB; # NOTE: we're overloading GL_NO_DAEMON_NO_GITWEB to mean "no git config" also. # In fact anything that requires trawling through the existing repos doing @@ -527,8 +569,6 @@ my %repo_patts = (); # update repo configurations, gitweb description, daemon export-ok, etc # ---------------------------------------------------------------------------- -# all these require a "chdir" to the repo, so we club them for efficiency - my %projlist = (); # for each real repo (and remember this will be empty, thus skipping all this, @@ -537,13 +577,13 @@ my %projlist = (); # note: we do them in 2 separate loops to avoid breaking the optimisation in # sub parse_acl (look for variable $saved_crwu) -for my $repo (keys %repo_patts) { +for my $repo (@phy_repos) { wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); # daemon is easy &setup_daemon_access($repo); } -for my $repo (keys %repo_patts) { +for my $repo (@phy_repos) { wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); # gitweb is a little more complicated. Here're some notes: # - "setup_gitweb_access" also sets "owner", despite the name @@ -562,9 +602,9 @@ for my $repo (keys %repo_patts) { # calls (setup daemon or gitweb). The reason is that they call # "can_read", which eventually calls parse_acl with the right "creator" # set for the *current* repo, which in turn stores translated values for - # $creator in the repo_config hash, which, (phew!) is needed for a match - # that eventually gets you a valid $repo_config{} below - &setup_repo_configs($repo, \%repo_config) if $repo_config{$repo}; + # $creator in the git_configs hash, which, (phew!) is needed for a match + # that eventually gets you a valid $git_configs{} below + &setup_git_configs($repo, \%git_configs) if $git_configs{$repo}; } # write out the project list diff --git a/t/out/t01-repo-groups.1 b/t/out/t01-repo-groups.1 index 38119e0..2124ba6 100644 --- a/t/out/t01-repo-groups.1 +++ b/t/out/t01-repo-groups.1 @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( 'aa' => { 'R' => { diff --git a/t/out/t01-repo-groups.1b b/t/out/t01-repo-groups.1b index 90c9850..3275bcf 100644 --- a/t/out/t01-repo-groups.1b +++ b/t/out/t01-repo-groups.1b @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( 'aa' => { 'R' => { diff --git a/t/out/t01-repo-groups.1bs b/t/out/t01-repo-groups.1bs new file mode 100644 index 0000000..944fac4 --- /dev/null +++ b/t/out/t01-repo-groups.1bs @@ -0,0 +1,116 @@ +$data_version = '1.7'; +%repos = (); +%split_conf = ( + 'aa' => 1, + 'bb' => 1, + 'gitolite-admin' => 1, + 'testing' => 1 +); +repositories/aa.git/gl-conf +repositories/bb.git/gl-conf +repositories/gitolite-admin.git/gl-conf +repositories/testing.git/gl-conf +%one_repo = ( + 'aa' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 2, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 4, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 5, + 'refs/.*', + 'RW' + ] + ] + } +); +%one_repo = ( + 'bb' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 3, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 6, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 7, + 'refs/.*', + 'RW' + ] + ] + } +); +%one_repo = ( + 'gitolite-admin' => { + 'R' => { + 'tester' => 1 + }, + 'W' => { + 'tester' => 1 + }, + 'tester' => [ + [ + 0, + 'refs/.*', + 'RW+' + ] + ] + } +); +%one_repo = ( + 'testing' => { + '@all' => [ + [ + 1, + 'refs/.*', + 'RW+' + ] + ], + 'R' => { + '@all' => 1 + }, + 'W' => { + '@all' => 1 + } + } +); diff --git a/t/out/t01-repo-groups.2 b/t/out/t01-repo-groups.2 index d766ca0..5b6a9aa 100644 --- a/t/out/t01-repo-groups.2 +++ b/t/out/t01-repo-groups.2 @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( '@g1' => { '@g1' => [ @@ -23,7 +23,21 @@ $data_version = '1.6'; '@g1' => 1, '@g2' => 1 } - }, + } +); +%groups = ( + '@g1' => { + 'aa' => 'master', + 'bb' => 'master' + } +); +%split_conf = ( + 'gitolite-admin' => 1, + 'testing' => 1 +); +repositories/gitolite-admin.git/gl-conf +repositories/testing.git/gl-conf +%one_repo = ( 'gitolite-admin' => { 'R' => { 'tester' => 1 @@ -38,7 +52,9 @@ $data_version = '1.6'; 'RW+' ] ] - }, + } +); +%one_repo = ( 'testing' => { '@all' => [ [ @@ -55,9 +71,3 @@ $data_version = '1.6'; } } ); -%groups = ( - '@g1' => { - 'aa' => 'master', - 'bb' => 'master' - } -); diff --git a/t/out/t02-user-groups.1 b/t/out/t02-user-groups.1 index d05ee68..05ba1fb 100644 --- a/t/out/t02-user-groups.1 +++ b/t/out/t02-user-groups.1 @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( 'aa' => { 'R' => { diff --git a/t/out/t02-user-groups.1b b/t/out/t02-user-groups.1b index d53203f..16d4f1b 100644 --- a/t/out/t02-user-groups.1b +++ b/t/out/t02-user-groups.1b @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( 'aa' => { 'R' => { diff --git a/t/out/t02-user-groups.1bs b/t/out/t02-user-groups.1bs new file mode 100644 index 0000000..54d8b4a --- /dev/null +++ b/t/out/t02-user-groups.1bs @@ -0,0 +1,79 @@ +$data_version = '1.7'; +%repos = (); +%split_conf = ( + 'aa' => 1, + 'gitolite-admin' => 1, + 'testing' => 1 +); +repositories/aa.git/gl-conf +repositories/gitolite-admin.git/gl-conf +repositories/testing.git/gl-conf +%one_repo = ( + 'aa' => { + 'R' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'W' => { + 'u1' => 1, + 'u2' => 1, + 'u3' => 1 + }, + 'u1' => [ + [ + 2, + 'refs/.*', + 'RW+' + ] + ], + 'u2' => [ + [ + 3, + 'refs/.*', + 'RW' + ] + ], + 'u3' => [ + [ + 4, + 'refs/.*', + 'RW' + ] + ] + } +); +%one_repo = ( + 'gitolite-admin' => { + 'R' => { + 'tester' => 1 + }, + 'W' => { + 'tester' => 1 + }, + 'tester' => [ + [ + 0, + 'refs/.*', + 'RW+' + ] + ] + } +); +%one_repo = ( + 'testing' => { + '@all' => [ + [ + 1, + 'refs/.*', + 'RW+' + ] + ], + 'R' => { + '@all' => 1 + }, + 'W' => { + '@all' => 1 + } + } +); diff --git a/t/out/t02-user-groups.2 b/t/out/t02-user-groups.2 index be82819..b4d5fd1 100644 --- a/t/out/t02-user-groups.2 +++ b/t/out/t02-user-groups.2 @@ -1,4 +1,4 @@ -$data_version = '1.6'; +$data_version = '1.7'; %repos = ( 'aa' => { '@g1' => [ diff --git a/t/out/t02-user-groups.2bs b/t/out/t02-user-groups.2bs new file mode 100644 index 0000000..0fc09d0 --- /dev/null +++ b/t/out/t02-user-groups.2bs @@ -0,0 +1,84 @@ +$data_version = '1.7'; +%repos = (); +%groups = ( + '@g1' => { + 'u1' => 'master' + }, + '@g2' => { + 'u2' => 'master', + 'u3' => 'master' + }, + '@g3' => { + 'u4' => 'master', + 'u5' => 'master', + 'u6' => 'master' + } +); +%split_conf = ( + 'aa' => 1, + 'gitolite-admin' => 1, + 'testing' => 1 +); +repositories/aa.git/gl-conf +repositories/gitolite-admin.git/gl-conf +repositories/testing.git/gl-conf +%one_repo = ( + 'aa' => { + '@g1' => [ + [ + 2, + 'refs/.*', + 'RW+' + ] + ], + '@g2' => [ + [ + 3, + 'refs/.*', + 'RW' + ] + ], + 'R' => { + '@g1' => 1, + '@g2' => 1 + }, + 'W' => { + '@g1' => 1, + '@g2' => 1 + } + } +); +%one_repo = ( + 'gitolite-admin' => { + 'R' => { + 'tester' => 1 + }, + 'W' => { + 'tester' => 1 + }, + 'tester' => [ + [ + 0, + 'refs/.*', + 'RW+' + ] + ] + } +); +%one_repo = ( + 'testing' => { + '@all' => [ + [ + 1, + 'refs/.*', + 'RW+' + ] + ], + 'R' => { + '@all' => 1 + }, + 'W' => { + '@all' => 1 + } + } +); diff --git a/t/t01-repo-groups b/t/t01-repo-groups index 367e29d..86c7231 100644 --- a/t/t01-repo-groups +++ b/t/t01-repo-groups @@ -39,8 +39,8 @@ echo " RW = u2 u3 " | ugc -catconf -expect_filesame $TESTDIR/out/t01-repo-groups.1 +catconfs +expect_filesame $TESTDIR/out/t01-repo-groups.1bs # ---------- $TESTDIR/rollback || die "rollback failed" @@ -54,7 +54,7 @@ echo " RW = @g2 " | ugc -catconf +catconfs expect_filesame $TESTDIR/out/t01-repo-groups.2 name INTERNAL diff --git a/t/t02-user-groups b/t/t02-user-groups index 7b673cc..3fabcbd 100644 --- a/t/t02-user-groups +++ b/t/t02-user-groups @@ -42,8 +42,8 @@ echo " RW = u2 u3 " | ugc -catconf -expect_filesame $TESTDIR/out/t02-user-groups.1 +catconfs +expect_filesame $TESTDIR/out/t02-user-groups.1bs # ---------- $TESTDIR/rollback || die "rollback failed" @@ -60,7 +60,7 @@ echo " RW = @g2 " | ugc -catconf -expect_filesame $TESTDIR/out/t02-user-groups.2 +catconfs +expect_filesame $TESTDIR/out/t02-user-groups.2bs name INTERNAL diff --git a/t/t59-repo-not-on-disk b/t/t59-repo-not-on-disk index 2873763..9f246f6 100644 --- a/t/t59-repo-not-on-disk +++ b/t/t59-repo-not-on-disk @@ -76,15 +76,21 @@ do cd ~/td name "repo on disk missing: u1" runlocal git clone u1:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to u1" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: tester" runlocal git clone gitolite:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to tester" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: u4" runlocal git clone u4:aa - expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "0" ] && expect "fatal: 'repositories/aa.git' does not appear to be a git repository" + [ "$bc" = "1" ] && expect "R access for aa DENIED to u4" + [ "$bc" = "1" ] && expect "Or there may be no repository at the given path. Did you spell it correctly?" name "repo on disk missing: u6" runlocal git clone u6:aa diff --git a/t/test-driver.sh b/t/test-driver.sh index 5d03753..78ba786 100755 --- a/t/test-driver.sh +++ b/t/test-driver.sh @@ -14,6 +14,13 @@ runremote() { ssh gitolite-test@localhost "$@" > ~/1 2> ~/2; } listrepos() { ssh gitolite-test@localhost find repositories -type d -name "*.git" | sort > ~/1 2> ~/2; } # remote cat compiled pm catconf() { ssh gitolite-test@localhost cat .gitolite/conf/gitolite.conf-compiled.pm > ~/1 2> ~/2; } +catconfs() { + ( + ssh gitolite-test@localhost cat .gitolite/conf/gitolite.conf-compiled.pm + ssh gitolite-test@localhost find repositories -name gl-conf \| sort + ssh gitolite-test@localhost find repositories -name gl-conf \| sort \| xargs cat + ) > ~/1 2> ~/2 +} # remote cat ~/.gitolite.rc catrc() { ssh gitolite-test@localhost cat .gitolite.rc > ~/1 2> ~/2; } # tail gitolite logfile |