The Concurrent Versions System, in its "pserver" client/server mode, and secured by "ssh" encrypted tunnels, can allow multiple authors to safely collaborate over the internet. CVS is a source file version control system optimised for wide area networks, concurrent editing, and reuse of 3rd party source libraries. Pserver is a protocol used for communication between CVS clients and servers. SSH is a tool to transparently encrypt TCP/IP network connections.
The tools discussed here are most functional in a unix environment but windows users can obtain similar functions by using a posix shell available from http://www.cygwin.com/. which will include an openssh package in 'latest' and a cvs package in 'contrib'. Other native windows ports of the tools are available but may lack needed features such as SSH2 DSA support.
If you are a contributing author, you don't need to know how the
repository was created. You may skip this section.
If you are the
unix repository administrator, you would create a directory and
run
cvs init
then adjust the control files in
CVSROOT to suit the permitted users (writers, passwd). It is
convenient to have all files owned by "cvsuser"
If you are a contributing author, you don't need to know how the repository server is started. You may skip this section. If you are the unix repository administrator, you allow the server to be started by xinetd with security constraints that specify that only clients local to the server machine may connect. To do this, create a configuration file named "/etc/xinetd.d/cvspserver" with contents similar to:
service cvspserver{flags = REUSEsocket_type = streamwait = nouser = cvsuserserver = /usr/bin/cvsserver_args = -f --allow-root=/cycomcvs pserverpassenv =log_on_failure += USERIDonly_from = 127.0.0.1bind = 127.0.0.1}
then restart the xinetd super-service.
Contributing authors must perform this step only once. The "ssh" tools have various ways of authenticating users. The method chosen here is to use the DSA Digital Signature Algorithm. This is a public/private keypair algorithm which means that the secret private key need never be communicated to anyone and can stay safe on the clients hard disk (protected by a passphrase). The public key can be advertised to anyone with no loss of security. If you do not already have the ssh tools then you should obtain them from http://www.openssh.com/. They must support SSH2 as we use the DSA algorithm not RSA.
A unix client will generate the keypair using:-
ssh-keygen
-t dsa
This will result in the creation of a file
"~/.ssh/id_dsa.pub". You must send this public file to the
unix repository administrator. Do not send any other file nor reveal
any passphrase.
If you are a contributing author, you don't need to know how
authorization is allowed. You may skip this section.
If you are
the unix repository administrator, on receipt of a clients
"id_dsa.pub" file, append the single line therein to the
"~cvsnobody/.ssh/authorized_keys2" file on the server. Note that some
linux systems use "authorized_keys2" as the file and some other systems
such as Solaris will use "authorized_keys". If one does not work try
the other. Note that the users home directory must not be writeable by
other users and that the private key files must not be readable by
other users.
CVS keeps a single copy of the master sources called a source repository. Remote authors access the repository using CVS client programs which talk to the repository service using a "pserver" protocol and connect using a registered TCP/IP port (port 2401).
The pserver protocol is insecure because passwords are transmitted unencrypted and there are often some hacked hosts on a network that are sniffing for passwords. The connection to be used for the pserver protocol therefore needs to be encrypted where it passes over any network. The "ssh" suite of programs provides such encrypted connections.
SSH will create a secure tunnel which makes the repository service appear to be local to your client machine. Similarly, your client machine will appear to be local to the repository service. Both client and server are fooled into thinking that they are on the same machine and that no traffic travels over any network.
The single line unix command to achieve this is:-
/usr/bin/ssh -v -a -L 2401:localhost:2401 cvsnobody@ns2.cyterm.com
Here is the output of an example session.
[cwturner@erika bin]$ /usr/bin/ssh -v -a -L
2401:localhost:2401 cvsnobody@ns2.cyterm.com
OpenSSH_3.5p1, SSH protocols 1.5/2.0, OpenSSL 0x0090701f
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Rhosts Authentication disabled, originating port will not be
trusted.
debug1: ssh_connect: needpriv 0
debug1: Connecting to ns2.cyterm.com [194.105.69.33] port 22.
debug1: Connection established.
debug1: identity file /home/cwturner/.ssh/identity type -1
debug1: identity file /home/cwturner/.ssh/id_rsa type -1
debug1: identity file /home/cwturner/.ssh/id_dsa type 2
debug1: Remote protocol version 1.99, remote software version
OpenSSH_2.5.2p2
debug1: match: OpenSSH_2.5.2p2 pat
OpenSSH_2.5.0*,OpenSSH_2.5.1*,OpenSSH_2.5.2*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_3.5p1
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-cbc hmac-md5 none
debug1: kex: client->server aes128-cbc hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: dh_gen_key: priv key bits set: 126/256
debug1: bits set: 999/2049
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
debug1: Host 'ns2.cyterm.com' is known and matches the RSA host key.
debug1: Found key in /home/cwturner/.ssh/known_hosts:2
debug1: bits set: 1034/2049
debug1: ssh_rsa_verify: signature correct
debug1: kex_derive_keys
debug1: newkeys: mode 1
debug1: SSH2_MSG_NEWKEYS sent
debug1: waiting for SSH2_MSG_NEWKEYS
debug1: newkeys: mode 0
debug1: SSH2_MSG_NEWKEYS received
debug1: done: ssh_kex2.
debug1: send SSH2_MSG_SERVICE_REQUEST
debug1: service_accept: ssh-userauth
debug1: got SSH2_MSG_SERVICE_ACCEPT
debug1: authentications that can continue: publickey,password
debug1: next auth method to try is publickey
debug1: try privkey: /home/cwturner/.ssh/identity
debug1: try privkey: /home/cwturner/.ssh/id_rsa
debug1: try pubkey: /home/cwturner/.ssh/id_dsa
debug1: input_userauth_pk_ok: pkalg ssh-dss blen 434 lastkey 0x8090310
hint 2
debug1: read PEM private key done: type DSA
debug1: ssh-userauth2 successful: method publickey
debug1: Connections to local port 2401 forwarded to remote address
localhost:2401
socket: Address family not supported by protocol
debug1: Local forwarding listening on 127.0.0.1 port 2401.
debug1: fd 4 setting O_NONBLOCK
debug1: channel 0: new [port listener]
debug1: channel 1: new [client-session]
debug1: send channel open 1
debug1: Entering interactive session.
debug1: ssh_session2_setup: id 1
debug1: channel request 1: pty-req
debug1: Requesting X11 forwarding with authentication spoofing.
debug1: channel request 1: x11-req
debug1: channel request 1: shell
debug1: fd 3 setting TCP_NODELAY
debug1: channel 1: open confirm rwindow 0 rmax 16384
Last login: Wed Jul 16 21:07:08 2003 from
chello212186208023.32.11.vie.surfer.at[cvsnobody@ns2 cvsnobody]$
Note that at this point you have an ssh shell session and prompt on
the remote server machine. When you later use a different window on the
client to use cvs, you will see further debug messages in the remote
session window like the following:-
debug1: fd 8 setting TCP_NODELAY
debug1: fd 8 setting O_NONBLOCK
debug1: channel 2: new [direct-tcpip]
debug1: channel 2: open confirm rwindow 32768 rmax 16384
debug1: channel 2: read<=0 rfd 8 len 0
debug1: channel 2: read failed
debug1: channel 2: close_read
debug1: channel 2: input open -> drain
debug1: channel 2: ibuf empty
debug1: channel 2: send eof
debug1: channel 2: input drain -> closed
debug1: channel 2: rcvd eof
debug1: channel 2: output open -> drain
debug1: channel 2: obuf empty
debug1: channel 2: close_write
debug1: channel 2: output drain -> closed
debug1: channel 2: send close
debug1: channel 2: rcvd close
debug1: channel 2: is dead
debug1: channel 2: garbage collecting
debug1: channel_free: channel 2: direct-tcpip: listening port 2401 for
localhost port 2401, connect from 127.0.0.1 port 34045, nchannels 3
debug1: Connection to port 2401 forwarding to localhost port 2401
requested.
debug1: fd 8 setting TCP_NODELAY
debug1: fd 8 setting O_NONBLOCK
debug1: channel 2: new [direct-tcpip]
debug1: channel 2: open confirm rwindow 32768 rmax 16384
debug1: channel 2: read<=0 rfd 8 len 0
debug1: channel 2: read failed
debug1: channel 2: close_read
debug1: channel 2: input open -> drain
debug1: channel 2: ibuf empty
debug1: channel 2: send eof
debug1: channel 2: input drain -> closed
debug1: channel 2: rcvd eof
debug1: channel 2: output open -> drain
debug1: channel 2: obuf empty
debug1: channel 2: close_write
debug1: channel 2: output drain -> closed
debug1: channel 2: rcvd close
debug1: channel 2: send close
debug1: channel 2: is dead
debug1: channel 2: garbage collecting
debug1: channel_free: channel 2: direct-tcpip: listening port 2401 for
localhost port 2401, connect from 127.0.0.1 port 34051, nchannels 3
The fixed
cvsnobody user is just for ssh tunneling purposes; it is not relevant
to CVS. The ns2.cyterm.com or j2ee.cycom.co.uk is the repository server
machine name.
If you used some batchmode flags to ssh then this command might block.
Otherwise you will see a shell prompt that shows you are logged in to
the remote server machine and you are able to type remote commands into
this window. Use the "exit" command when you wish to close the tunnel.
Use another window to operate the CVS clients.
In the terminal window that is logged on the remote machine, you can
check that cvspserver is listening on its local interface using
netstat. E.g.
[cvsnobody@ns2 cvsnobody]$ netstat -tl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local
Address
Foreign Address State
tcp
0 0 localhost.lo:cvspserver
*:*
LISTEN
...
Also on the local client machine you can check that the cvspserver
port is being listened to even though no cvsserver is running on the
client. E.g.
[cwturner@erika cwturner]$ netstat -tl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local
Address
Foreign Address State
tcp
0 0
*:32768
*:*
LISTEN
tcp
0 0 erika.locald:cvspserver
*:*
LISTEN
If you are trying to test this using the same machine for client and server then you will need to use different ports for the real cvs server and the forwarded connection. In the above examples the 2401 default pserver port was used for both client and server. You will need to change the clients port to something else (say 2402) when you simulate on a single machine. E.g.
/usr/bin/ssh -v -a -L 2402:localhost:2401
cvsnobody@localhost
Also ensure you then have the new port set in the appropriate CVSROOT environment content and CVS/Root contents which match the new client ports. E.g.
:method:[[user][:password]@]hostname[:[port]]/path/to/repository
or set and export the CVS_CLIENT_PORT environment variable before all client commands. E.g.
[cwturner@erika cycom]$ export CVS_CLIENT_PORT=2402
[cwturner@erika cycom]$ cvs login
Logging in to :pserver:cwturner@localhost:2402/cycomsites
CVS password:
[cwturner@erika cycom]$
Having established a tunnel, the remote CVS repository service now appears to be local to your client machine (i.e. at localhost). The CVS client programs obtain configuration data from a CVSROOT environment variable which should be set in unix (e.g in your ".bash_profile") using:-
CVSROOT=':pserver:jsharp@localhost:/cycomcvs'export CVSROOT
The username "jsharp" and the repository root
"/cycomcvs" will have been sent to you by the repository
administrator.
The first CVS client command should always be:-
cvs
login
You will be prompted for a password (again sent to
you by the repository administrator).
To create a new cvs working directory and populate it from Honest John Car Rental Demo sources, use :-
mkdir myworkcd myworkcvs co hjvhcvs co hjvhearcvs co hjvhmodel
To freshen an existing working directory with updates from other authors, use:-
cd mywork/hjvhcvs update
To publish the files that you have changed in an existing working directory, use:-
cd mywork/hjvhcvs commit
To publish a newly created file in an existing working directory, use:-
cd mywork/hjvhcvs add mynewfile.txtcvs commit
To import a new independent directory tree of sources into the repository, make sure all files in the tree are useful source and then use:-
cd projdircvs import projdir projV1_1 proj_V1_1cd ..mv projdir origprojsourcescvs co projdir
CVS (http://cvshome.org/)has an extensive FAQ, postscript manuals and other documentation which should be consulted. There are client ports to MSWindows and Java platforms . SSH (http://www.openssh.com/ ) tools have client ports to MSWindows and DOS.
A similar article discusses securing your mail via SSH
Author: Chris Turner