We currently use CVS to maintain some open source projects and internal projects. We sometimes port these projects to clients' systems/targets by ssh-ing into their systems and using the CVS repository back on our host systems. A few external contributors have either read or write access to the open source repositories. Access is presently enforced via honor code. In our current set up, we have an outward-facing firewalled system where the open source repository lives. Users access this system via ssh and each user has a login on the firewall'ed system. Works fine, though setting up a new system account for each user is a bit of pain, when all we really want to do is allow CVS access. If we are working on another site and want to access our proprietary CVS, we really have no easy way of doing that, though "CVS server pipelining" (which I read about recently in the FAQ) might be able to accomplish that. And ssh port forwarding might work as well, but would require new keys and/or a new system account to make it work.
We'd like to move all the CVS repositories onto one internal CVS server and manage it there, using the pserver access method. We'd also like to use the "alternate user" capability of pserver so that all accesses within a given tree are restricted to a particular user/group. We'd have a different user group for the "public" (open source) tree than the "local" (proprietary) tree simply as another layer of access enforcement. We also plan to have two separate pserver IP ports: one for the public tree, and one for the local tree. From what I've read, we can access our internal pservers by transiting through our firewall servers by using ssh port forwarding. Although port forwarding works, it is a bit clunky. Also, we'd prefer not to disturb our current external developers (who are using ssh into the firewall machine and the :ext: server protocol). We'd use --allow-root and xinetd to handle those restricted accesses in the usual way. Doing a little research, I noticed that pserver and server share the same CVS transaction protocol, except for the "front end" of the protocol where pserver authenticates and :ext: server does not. It seemed to me that it might be possible to write a "server to pserver" protocol converter, that talks to an :ext:server client on side and that translates those requests to a pserver in a meaningful way. To demonstrate how this might be done, I've sketched out the basics as I understand them. === cvspsproxy - a cvs server proxy that connects to a pserver cvspsproxy supports connections from CVS clients using the :ext: server protocol. cvspsproxy will in turn connect to a psercer, obtaining the pserver specification by reading the various :ext:server specifications from stdin, utilizing the server protocol. The pserver user, host, and password will be extracted from the ~/.cvspass file. This authentication information is then sent to the pserver. Once authenticated cvspsproxy simply passes data between the client and the pserver. This works because the pserver and server protocols are identical once the client has been authenticated. Cvspsproxy is intended for use via an ssh connection, but can be used in other contexts as well. Design ------ 1. Read and parse initial server commands, up to the "Root" command: - Root pathname \n The Root request must be sent only once, and it must be sent before any requests other than Valid-responses, valid-requests, UseUnchanged, Set, Global_option, init, noop, or version - Valid-responses request-list \n - Valid-requests \n (server sends back list of requests it can process) cvspsproxy will have to send a string of valid requests that are supported, if this is sent before authentication. - UseUnchanged \n - Set variable=value \n - Global_option option \n - init root-name \n This will have to be unsupported because the pserver has no way to veriyf access if no CVS root exists yet. - noop Send back any pending errors, pending Notified reponses - version Send back version string. In order to get the valid requests response and version response correct, cvspsproxy should be built withn the CVS build tree, using its sources. All of the commands listed above can be sent by the client before sending the Root request. Once the root request is sent: 1. Look it up the .cvspass file and obtain the following info. that will be sent to the pserver for authentication purposes: (1) user, (2) password, (3) host, (4) port. 2. Connect to the host on the given port. 3. Send the string `BEGIN AUTH REQUEST', a linefeed, the cvs root, a linefeed, the username, a linefeed, the password trivially scrambled, a linefeed, the string `END AUTH REQUEST', and a linefeed. 4 Pserver replies with: * I LOVE YOU - continue with server protocol, working as a pure proxy simply passing packets back-forth between the user client and the pserver. * I HATE YOU - close the connection * E text - send back this response and all following E responses * error code text - send to cliet and close connection The .cvspass check could be augmented by 1. a -d switch 2. a CVSROOT environment variable 3. and then the .cvspass check Certain consistency checks may be required to ensure that the Root specified by the server is the same root as that sent to the pserver. === Does that sound feasible/useful? If it does, and someone with knowledge of CVS internals has an interest to develop this idea further, I'd be glad to help test and debug the result (but don't have time right now write the code). thanks, - Gary