This document is for Savannah administrators, not Savannah users. Savannah is a SourceForge clone based on the SourceForge-2.0 software. It is dedicated the GNU projects.
Because of the highly specific nature of the software, Savannah is a fork of the SourceForge-2.0 software. Attempting to make it modular and configurable is a waste of time. The whole Savannah software is available from CVS and is managed by the Savannah project. The ChangeLog explains the modifications made to the original code.
--- The Detailed Node Listing ---
CVS repositories
Database
System Administration
Savannah currently provides the CVS frontend. Check the Task List for details on planned developments.
Setting up Savannah is not an easy task because it has to integrate existing habits and projects without breaking anything. However, the SourceForge Installation Guide by Guillaume Morin helps a lot understanding the software.
Savannah is installed on the machine subversions.gnu.org. The root of the installation is in /subversions/sourceforge. All the software that is not system wide and is needed to run Savannah is installed in this directory. The structure of this directory is similar to FHS-2.1. In the following table the path names are relative to the installation root. All directories covered by the SourceForge Installation Guide are omitted.
tmp
src/savannah
src/savannah/www
src/savannah/gnuscripts
The whole Savannah software is available from CVS and is managed by the Savannah project.
In order to install changes commmited in the savannah project CVS tree, proceed as follows:
login subversions su - export CVS_RSH=ssh cd /subversions/sourceforge/src/savannah cvs -q update
For each project registered on Savannah there may be two CVS repositories. One to store the sources of the project and one to store the web of the project. The sources repository is in /subversions/cvs/software and the web repository is in /subversions/cvs/gnuweb. The /webcvs symbolic link points to /subversions/cvs/gnuweb and the /cvsroot symbolic link points to /subversions/cvs/software.
Existing projects that migrate to Savannah may want their CVS repository to be transfered to subversions. Time is essential for such an operation since the project contributors want to work on the new repository on subversions and stop using the old. When the author asks cvs-hackers@gnu.org, ask him to send the tarbal by mail or send a URL from which it can be downloaded. Make an appointement with him and guarantee that the repository will be untared on subversions with 24 hours maximum. The project contributor must first create a project on subversions. When you have the tarbal untar it at /cvsroot/project. Make sure it does not contain a CVSROOT that would override the existing CVSROOT. If it does manualy copy the history and val-tags files only. Make sure the imported repository is untared under /cvsroot/project/project and does not polute the root of the repository.
When a project has a license that is not website
a source
repository is created under /subversions/cvs/software/project with
a private CVSROOT that only contains anoncvs. The developers of the
project have access to the CVSROOT directory.
The group project
is created to grant write access to the repository
to all the members of the project.
When a Savannah project is assigned the website
license, it only
has a portion of the webcvs repository and no source CVS repository.
If the html_cvs
field for a given Savannah project is empty, it
is not associated with a part of the webcvs repository.
It allows them to add commit notification by doing the following,
replacing project
with the name of their project:
cvs -d subversions.gnu.org:/cvsroot/project co CVSROOT In CVSROOT/commitinfo ^project /usr/local/bin/commit_prep -T project -r In CVSROOT/loginfo ^project /usr/local/bin/log_accum -T project -C -m project-commit@gnu.org -s %{sVv}
The email address must exist, it will not be automatically generated.
For compatibility with the cvs setup before Savannah was introduced, /subversions/cvs/common contains repositories that existed before Savannah. When a project is registered in Savannah, a symbolic link is created (/subversions/cvs/software/project/project) that points to the already existing /subversions/cvs/common/project directory.
The /cvs symbolic link points to /subversions/cvs/common so that people already using it to access their repositories can continue to do so. Before Savannah existed a pserver access was available and Savannah continues to maintain it for these projects, updating the CVSROOT/passwd files with user/password pairs that are in the Savannah database.
When a project has an html_cvs
field that is not empty in the
group
table, a web repository is created in
/subversions/cvs/gnuweb/html_cvs
. By default the html_cvs
field has the value /software/project/
but it may be edited with
the savannah.gnu.org/admin/. See the gnujobs, greve and bravegw projects
for examples.
When a Savannah project is assigned the website
license, it only
has a portion of the webcvs repository and no source CVS repository.
If the html_cvs
field for a given Savannah project is empty, it
is not associated with a part of the webcvs repository.
The group webproject
is created to grant write access to the repository
to all the members of the project.
All the www.gnu.org web was imported in /subversions/cvs/gnuweb.
When a project is registered on Savannah and there already exists
a directory for it in the repository (either .../software/project or
the value of the html_cvs
field), a chgrp -R webproject is done
on this repository to grant the members of the project a write access
to this portion of the web repository and only this one.
The www
project in Savannah is treated in a special way. All the
members of the www
project have access to the whole repository
in /webcvs. It means that they are always included in every webproject
created.
Since CVS is not able to handle symbolic links, a simple mechanism has been implemented on the machine hosting the www.gnu.org to allow webmasters to control the symbolic link from the CVS tree.
The special file .symlinks
contains a list of file name pairs,
one per line. For instance:
foo.html index.html bar.html other.html
is a valid .symlinks
file. Every night a script reads all the
.symlinks
files, prepend a ln -s
in front of each line
and execute them. Well, in reality it's not that simple but you get
the idea. The .symlinks
file can only be used to control the
symbolic link in the directory where they are. File names with / will
be ignored.
The /subversions/cvs/gnuweb/CVSROOT/loginfo file contains triggers that update the gnudist.gnu.org:/home/www/html directory whenever a commit is done. There is a single CVSROOT for all the projects that have a web repository.
When a top level directory is added in the webcvs repository a line must be added in the loginfo file to run webcvs whenever something is changed in this directory. This must be done manualy. Hopefully adding new top level directories is not a frequent operation and adding this is not too much overhead for the Savannah maintainer.
The special project www
have write access to all the /webcvs
repository. It is possible to create projects that will limit write
access of the members of the project to a subdirectory of the /webcvs
repository only. For instance the bravegw
Savannah project only
give write access to the /webcvs/brave-gnu-world part of the repository.
A project bound to a specific subdirectory will grante write access to all the tree under this subdirectory. There is no way, for instance, to grant write access to group B to /webcvs/thispart and write access to group A to /webcvs/thispart/subdir. If you do this group B win and will have write access to /webcvs/thispart recursively and group A will have access to nothing. If you see a way to overcome this limitation, let us know.
The sf_www script generates the map that is published at www.gnu.org to Savannah. It writes the file in /subversions/sourceforge/src/server/standards and commits it. The server/standards directory is a read-write checkout of the www.gnu.org web CVS. The sf_www script is run once a day by the crontab.
A more webmaster oriented documentation explains the organisation of the www.gnu.org CVS tree and the rationale of its usage.
Savannah uses MySQL and the sourceforge
database. The root user has
a ~/.my.cnf file that defines the user/passwd. It is not necessary to
specify them on the command line.
The tables people_skill
and people_skill_level
are loaded
from the skill database maintained by CJN (http://cjn.sourceforge.net/).
The script /subversions/sourceforge/src/savannah/gnuscripts/sf_skill
loads the XML skill files from CJN and replace the content of the
tables in the sourceforge database.
If some proprietary software shows on the skill list, add it to the %ignore table in the sf_skill script and re-run it.
cd /subversions/sourceforge/src/savannah/gnuscripts edit sf_skill sf_skill cvs commit -m 'Ignore proprietary software xxxx'
Savannah will try to send mail to users under various circumstances (bug reports notification, account creation etc.). In some cases it will use the real mail address of the user, in others it will use user@savannah.gnu.org. In order for the user@savannah.gnu.org address to work properly for outgoing mails, the /etc/aliases file is updated automatically every 5 minutes with the following command:
sf_aliases
The user@savannah.gnu.org can never
be used to recieve mail for
the good reason that savannah.gnu.org does not listen on the SMTP port.
People who have a simple alias name@gnu.org but no account on Kerberos cannot create an account on Savannah. When they ask to unlock the account name on savannah-hackers@gnu.org, tell them to create an account using a fake username and to send this username to savannah-hackers@gnu.org. When receiving that user name substitute the fake login name by the desired one:
mysql -e "update user set user_name = 'desired' where user_name = 'fake'" sourceforge
Must be root to run this script. You are advised to run it in /subversions/sourceforge/tmp, although it is not mandatory.
The sf_migrate
script creates a Savannah project for an existing project
in the /subversions/cvs/common directory. It is done in three steps:
--add
When explaining the situation to a user added to Savannah in this
way, one could say it like this. If you have a Kerberos account on
gnu.org, use the same login and password on Savannah and change the
password immediately afterwards: it will not change your Kerberos
password, just the Savannah password. If you only have a pserver
account, use the same login and password on Savannah. If you have
both, use the Kerberos account login and password. If you have none
and access CVS using SSH public keys, ask to cvs-hackers@gnu.org to
give you a password. This last case requires human interaction to
prevent someone from stealing your account name.
--bind
--mail
When a user with SSH access thru public key was added by sf_migrate, she/he will be instructed to ask for a password to cvs-hackers@gnu.org. The sf_pass script can be used to set her/his password. A mail must be sent by the user requesting the password with the encrypted password. Instruct the user to generate the password using the following command:
perl -e 'print crypt("mypassword", join "", (".", "/", 0..9, "A".."Z", "a".."z")[rand 64, rand 64])'
When the user send the password crypted, set it using:
sf_pass --set thename cryptpass | mysql sourceforge
After 24 hours, check user logged in and lock the user if it is not the case. This is to prevent obvious holes.
sf_pass --unset thename | mysql sourceforge
Must be root to run this script. Must export CVS_RSH=ssh. You are advised to run it in /subversions/sourceforge/tmp, although it is not mandatory.
The sf_cvs
script generates a shell script that will synchronize
the system files with the state of the Savannah database (sourceforge).
This script only generates lines if something needs to be done. When
the resulting script is executed, another run must not
display
any action, unless the database was modified in the meantime.
It performs the following tasks, in this order.
Add new projects
Update existing projects
Add missing users
Remove users
Update existing users
Update the CVS password file
Update xinetd.conf
The HTML version of this document is published in two places: Savannah Administration Guide and Savannah Administration Guide. The source is stored in the subversions.gnu.org:/cvs co gnudocs repository. To facilitate the publication process you can edit it in the subversions.gnu.org:/subversions/sourceforge/src/gnudocs directory and then issue a
make publish
The publish
goal assumes that the Savannah document root is in
../savannah/www and a read-write checkout of the www.gnu.org/server/standards
directory is in ../server/standards. It will format the document to
HTML and commit the changes to the repository.
The SSL certificate for savannah.gnu.org was generated in /etc/apache-ssl/. Check the README file for a log of the command. There has been a lot of discussions regarding the root certificate for GNU, the use of a PKI. At some point the savannah certificate will be generated using a proper root certificate.
The Savannah crontab jobs are in /etc/cron.d/savannah. Every cron command output is sent to savannah-hackers@gnu.org.
*/5 * * * * root sf_aliases 10 4 * * * root sf_www 17 * * * * root cd /subversions/sourceforge/tmp ; sf_cvs | ( date ; sh -x ) >> /var/log/sf_cvs.log 2>&1
All software that is not system wide but only used for the purpose of Savannah must be installed in the prefix /subversions/sourceforge.
The MySQL installation is an exception that must be fixed. It is installed with the /usr/local/mysql prefix. It was not installed from the debian package because I (loic@gnu.org) was not able to fix the MySQL-3.23 package to make it work on potato.
The large number of groups a user can have (>32) implies to modify some basic programs (namely useradd and usermod).
Gordon Matzigkeit <gord@fig.org> modified /usr/local/src/cvs-1.10.8/src/server.c to overcome the limit builtin glibc. He also installed the /boot/vmlinuz-2.2.12-256groups kernel that was compiled with NGROUPS_MAX set to 256. The system files have not been reinstalled to match this version.
Here is the patch applied to /usr/local/src/shadow-19990827. The modified usermod and useradd have been installed in /subversions/sourceforge/bin.
*** ./debian/rules.~1~ Fri Feb 9 02:05:06 2001 --- ./debian/rules Fri Feb 9 02:05:41 2001 *************** *** 38,44 **** ifneq ($(DEB_HOST_GNU_SYSTEM),gnu) include debian/scripts/login.mk package-list += binary-login ! config_options += --with-libpam control_defs += -DMODDEP="(>= 0.72-5)" endif --- 38,44 ---- ifneq ($(DEB_HOST_GNU_SYSTEM),gnu) include debian/scripts/login.mk package-list += binary-login ! # config_options += --with-libpam control_defs += -DMODDEP="(>= 0.72-5)" endif *** ./build-tree/shadow-19990827/libmisc/addgrps.c.~1~ Mon Dec 28 12:34:41 1998 --- ./build-tree/shadow-19990827/libmisc/addgrps.c Fri Feb 9 03:04:47 2001 *************** *** 20,25 **** --- 20,28 ---- * already there. Warning: uses strtok(). */ + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + int add_groups(const char *list) { *** ./build-tree/shadow-19990827/src/usermod.c.~1~ Fri Jul 9 09:27:38 1999 --- ./build-tree/shadow-19990827/src/usermod.c Fri Feb 9 03:05:52 2001 *************** *** 74,79 **** --- 74,82 ---- #define VALID(s) (strcspn (s, ":\n") == strlen (s)) + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + static char *user_name; static char *user_newname; static char *user_pass; *** ./build-tree/shadow-19990827/src/groups.c.~1~ Mon Jun 7 09:40:45 1999 --- ./build-tree/shadow-19990827/src/groups.c Fri Feb 9 03:15:54 2001 *************** *** 42,47 **** --- 42,50 ---- static void print_groups P_((const char *)); int main P_((int, char **)); + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + /* * print_groups - print the groups which the named user is a member of * *** ./build-tree/shadow-19990827/src/id.c.~1~ Mon Jun 7 09:40:45 1999 --- ./build-tree/shadow-19990827/src/id.c Fri Feb 9 03:16:34 2001 *************** *** 50,55 **** --- 50,58 ---- static void usage P_((void)); int main P_((int, char **)); + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + static void usage(void) { *** ./build-tree/shadow-19990827/src/useradd.c.~1~ Fri Feb 9 02:06:01 2001 --- ./build-tree/shadow-19990827/src/useradd.c Fri Feb 9 03:28:52 2001 *************** *** 53,58 **** --- 53,61 ---- #endif #include "faillog.h" + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + #ifndef SKEL_DIR #define SKEL_DIR "/etc/skel" #endif *** ./build-tree/shadow-19990827/src/newgrp.c.~1~ Fri Feb 9 02:06:00 2001 --- ./build-tree/shadow-19990827/src/newgrp.c Fri Feb 9 03:29:10 2001 *************** *** 49,54 **** --- 49,57 ---- static GETGROUPS_T *grouplist; #endif + #undef NGROUPS_MAX + #define NGROUPS_MAX 256 + static char *Prog; static int is_newgrp;
The sshd daemon has been rebuilt with the following patch so that CVS ssh operations have the proper set of groups. The sources are in /usr/local/src/openssh-1.2.3/ and the corresponding debian package is at /usr/local/src/ssh_1.2.3-9.2loic_i386.deb. The package was tagged on hold using dselect to prevent accidental upgrade. Note that this patch may have hideous impact for users who have real account and use ssh since most of the commands that deal with groups have not been recompiled to handle more than the limit of 32 groups. For instance the id command will core dump. Here is the patch applied on the distribution:
*** sshd.c.~1~ Fri Mar 17 04:40:18 2000 --- sshd.c Tue Feb 13 06:32:17 2001 *************** *** 147,152 **** --- 151,240 ---- const char *display, const char *auth_proto, const char *auth_data, const char *ttyname); + #ifdef AUTH_SERVER_SUPPORT + #ifdef HAVE_GETSPNAM + #include <shadow.h> + #endif + #endif /* AUTH_SERVER_SUPPORT */ + + /* The GNU C Library currently has a compile-time limit on the number of + groups a user may be a part of, even if the underlying kernel has been + fixed, and so we define our own initgroups. */ + #include <grp.h> + static int + xinitgroups (char *user, gid_t gid) + { + struct group *grp; + gid_t *buf; + int buflen, ngroups; + + /* Initialise the list with the specified GID. */ + ngroups = 0; + buflen = 16; + buf = malloc (buflen * sizeof (*buf)); + buf[ngroups ++] = gid; + + setgrent (); + while ((grp = getgrent ())) + { + /* Scan the member list for our user. */ + char **p = grp->gr_mem; + while (*p && strcmp (*p, user)) + p ++; + + if (*p) + { + /* We found the user in this group. */ + if (ngroups == buflen) + { + /* Enlarge the group list. */ + buflen *= 2; + buf = realloc (buf, buflen * sizeof (*buf)); + } + + /* Add the group id to our list. */ + buf[ngroups ++] = grp->gr_gid; + } + } + endgrent (); + + /* Return whatever setgroups says. */ + buflen = setgroups (ngroups, buf); + free (buf); + return buflen; + } + #define initgroups xinitgroups + + /* This worked fine, and was adopted into glibc, until setgroups got a + similar limitation, so we override it as well. */ + #include <linux/posix_types.h> + #include <sys/syscall.h> + #include <errno.h> + + int + setgroups (size_t n, const gid_t *groups) + { + size_t i; + __kernel_gid_t kernel_groups[n]; + + for (i = 0; i < n; i ++) + kernel_groups[i] = groups[i]; + + { + long res; + __asm__ volatile ("int $0x80" + : "=a" (res) + : "0" (__NR_setgroups),"b" ((long)(n)), + "c" ((long)(kernel_groups))); + + if ((unsigned long)(res) >= (unsigned long)(-125)) { + errno = -res; + res = -1; + } + return (int) (res); + } + } + /* * Remove local Xauthority file. */