bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

CVS & SSL


From: Derek R. Price
Subject: CVS & SSL
Date: Mon, 21 May 2001 10:48:54 -0400

Hey all,

I spent a few days trying to get CVS working with SSL.

My solution was actually pretty simple - use a hook very similar to the
:ext: (RSH) hook to launch (OpenSSL's?) stunnel application and use the
resulting connection like a pserver connection.  No changes were needed
on the server side - the server just needed stunnel to be used as an
SSL filter between it and the port in question via inetd, tcpserver, or
stunnel's built in daemonizing mechanism.

Anyway, I had almost everything working - I can use an stunnel session
from the command prompt to talk to the CVS server and everything looks
dandy.  The CVS client will happily launch stunnel and the server sees
the data sent by the client but the server's response gets lost.  There
are some funny messages from stunnel in the syslog which I don't
understand too.

Anyway, I've run out of time to work on fixing what looks like a stupid
stunnel bug for maybe a few months.  It'd be a shame to lose this if the
fix really is simple.  Anyhow, I'm including the patch in case anyone
else has time to look into it.

Please let me know if you decide to spend time on this so I know who to
talk to if I decide to get back to it in a few months.  Also, if anyone
wants to take the time to fill out IANA ( http://www.iana.org )'s port
assignment request for cvssserver or cvsssl or something like that, the
help is appreciated, but let me know about that too so the request
doesn't get submitted twice.  Feel free to use webmaster@cvshome.org or
my email address @cvshome.org (dprice@cvshome.org) on the cc list or as
the submitter.

The patch I've included applies against the development version of CVS.
I wouldn't try it against 1.11.1p1 or earlier myself since I made a
bunch of changes to the dev tree which this patch depends on.

Derek

--
Derek Price                      CVS Solutions Architect ( http://CVSHome.org )
mailto:dprice@collab.net         CollabNet ( http://collab.net )
--
I will not prescribe medication.
I will not prescribe medication.
I will not prescribe medication...

          - Bart Simpson on chalkboard, _The Simpsons_


Index: src/client.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/client.c,v
retrieving revision 1.304
diff -u -r1.304 client.c
--- src/client.c        21 May 2001 12:55:38 -0000      1.304
+++ src/client.c        21 May 2001 14:12:36 -0000
@@ -3742,6 +3742,8 @@
        case gserver_method:
        case pserver_method:
            return get_port_number ("CVS_CLIENT_PORT", "cvspserver", 
CVS_AUTH_PORT);
+       case sserver_method:
+           return get_port_number ("CVS_CLIENT_PORT", "cvssserver", 
CVS_SAUTH_PORT);
 #ifdef HAVE_KERBEROS
        case kserver_method:
            return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT);
@@ -3791,6 +3793,9 @@
        /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
           fdopening the same file descriptor twice, so dup it if it is the
           same.  */
+       if (trace)
+           fprintf (stderr, " -> tofd = %d : fromfd = %d\n", tofd, fromfd);
+
        if (tofd == fromfd)
        {
            fromfd = dup (tofd);
@@ -4375,6 +4380,12 @@
             */
            connect_to_pserver (current_parsed_root, &to_server, &from_server, 
0, 0);
            break;
+       case sserver_method:
+           /* Toss the return value.  It will die with an error message if
+            * anything goes wrong anyway.
+            */
+           connect_to_sserver (current_parsed_root, &to_server, &from_server, 
0, 0);
+           break;
 #endif
 
 #if HAVE_KERBEROS
@@ -4922,6 +4933,215 @@
 # endif /* START_RSH_WITH_POPEN_RW */
 
 #endif /* NO_EXT_METHOD */
+
+
+
+/* static char *
+ * format_sserver_cmdline (char *fmt)
+ *
+ * This function turns a format string into a command line for launching
+ * some sort or socket connection.
+ *
+ * INPUTS
+ *   fmt       Format string
+ *
+ * Replaces:
+ *   %h                hostname
+ *   %p                port number
+ *
+ * RETURNS
+ *   Pointer to newly allocated string.
+ *
+ * NOTES
+ *   If something like this is to be done often, this function should be
+ *   replaced with the more general format_cmdline function from my (Derek
+ *   Price's) newfmtstrings patch.
+ */
+static char *
+format_sserver_cmdline (fmt, root)
+    char *fmt;
+    cvsroot_t *root;
+{
+    size_t lout = 0;
+    char *out = NULL;
+    char *s = fmt;
+    ptrdiff_t doff = 0;
+    char tmp[10];
+
+    while (*s)
+    {
+       switch (*s)
+       {
+           case '\\':
+               if (*(s + 1))
+               {
+                   expand_string (&out, &lout, lout + 2);
+                   *(out + doff++) = *++s;
+               }
+               break;
+           case '%':
+               if (*(s + 1))
+               {
+                   switch (*++s)
+                   {
+                       case '%':
+                           expand_string (&out, &lout, lout + 2);
+                           *(out + doff++) = *s;
+                           break;
+                       case 'h':
+                           xrealloc_and_strcat(&out, &lout, root->hostname);
+                           doff += strlen (root->hostname);
+                           break;
+                       case 'p':
+                           sprintf (tmp, "%d", root->port);
+                           xrealloc_and_strcat(&out, &lout, tmp);
+                           doff += strlen (tmp);
+                           break;
+                       default:
+                           error (1, 0, "Unrecognized format string in 
CVS_SOCKETEER, %%'%c'\n", *s);
+                           break;
+                   }
+               }
+               break;
+           default:
+               expand_string (&out, &lout, lout + 2);
+               *(out + doff++) = *s;
+               break;
+       }
+       s++;
+    }
+    return (out);
+}
+
+
+
+void
+connect_to_sserver (root, to_server_p, from_server_p, verify_only, do_gssapi)
+    cvsroot_t *root;
+    struct buffer **to_server_p;
+    struct buffer **from_server_p;
+    int verify_only;
+    int do_gssapi;
+{
+    /* If you're working through firewalls, you can set the
+       CVS_RSH environment variable to a script which uses rsh to
+       invoke another rsh on a proxy machine.  */
+    char *cvs_socketeer = getenv ("CVS_SOCKETEER");
+    char *command;
+    int tofd, fromfd;
+    struct buffer *to_server, *from_server;
+    int child_pid;
+
+    char *log = getenv ("CVS_CLIENT_LOG");
+
+    if (!cvs_socketeer)
+       cvs_socketeer = "stunnel -cr%h:%p";
+
+    command = format_sserver_cmdline (cvs_socketeer, root);
+
+    /* FIXME: This doesn't handle spaces in command except as delimiters */
+    {
+        char *argv[10];
+       char **p = argv;
+       char *ptrptr, *tok;
+
+       tok = strtok_r (command, " \t\r\n", &ptrptr);
+       while (tok)
+       {
+           *p++ = tok;
+           tok = strtok_r (NULL, " \t\r\n", &ptrptr);
+       }
+
+       *p++ = NULL;
+
+       if (trace)
+        {
+           int i;
+
+            fprintf (stderr, " -> Starting server: ");
+           for (i = 0; argv[i]; i++)
+               fprintf (stderr, "%s ", argv[i]);
+           putc ('\n', stderr);
+       }
+
+       child_pid = piped_child (argv, &tofd, &fromfd);
+
+       if (child_pid < 0)
+           error (1, errno, "cannot start server via socketeer");
+    }
+    free (command);
+
+    make_bufs_from_fds (tofd, fromfd, child_pid, &to_server, &from_server);
+
+    /* Set up logfiles, if any.
+     *
+     * We do this _after_ authentication on purpose.  Wouldn't really like to
+     * worry about logging passwords...
+     */
+    if (log)
+    {
+       int len = strlen (log);
+       char *buf = xmalloc (len + 5);
+       char *p;
+       FILE *fp;
+
+       strcpy (buf, log);
+       p = buf + len;
+
+       /* Open logfiles in binary mode so that they reflect
+          exactly what was transmitted and received (that is
+          more important than that they be maximally
+          convenient to view).  */
+       /* Note that if we create several connections in a single CVS client
+          (currently used by update.c), then the last set of logfiles will
+          overwrite the others.  There is currently no way around this.  */
+       strcpy (p, ".in");
+       fp = open_file (buf, "wb");
+        if (fp == NULL)
+           error (0, errno, "opening to-server logfile %s", buf);
+       else
+           to_server = log_buffer_initialize (to_server, fp, 0,
+                                              (BUFMEMERRPROC) NULL);
+
+       strcpy (p, ".out");
+       fp = open_file (buf, "wb");
+        if (fp == NULL)
+           error (0, errno, "opening from-server logfile %s", buf);
+       else
+           from_server = log_buffer_initialize (from_server, fp, 1,
+                                                (BUFMEMERRPROC) NULL);
+
+       free (buf);
+    }
+
+    auth_server (root, to_server, from_server, verify_only, do_gssapi, NULL);
+
+    if (verify_only)
+    {
+       int status;
+
+       status = buf_shutdown (to_server);
+       if (status != 0)
+           error (0, status, "shutting down buffer to server");
+       status = buf_shutdown (from_server);
+       if (status != 0)
+           error (0, status, "shutting down buffer from server");
+
+       buf_free (to_server);
+       buf_free (from_server);
+
+       /* Don't need to set server_started = 0 since we don't set it to 1
+        * until returning from this call.
+        */
+    }
+    else
+    {
+       *to_server_p = to_server;
+       *from_server_p = from_server;
+    }
+
+    return;
+}
 
 
 
Index: src/client.h
===================================================================
RCS file: /home2/cvsroot/ccvs/src/client.h,v
retrieving revision 1.39
diff -u -r1.39 client.h
--- src/client.h        6 May 2001 00:02:37 -0000       1.39
+++ src/client.h        21 May 2001 14:12:36 -0000
@@ -64,9 +64,16 @@
                                struct buffer **,
                                struct buffer **,
                                int, int ));
+void connect_to_sserver PROTO ((cvsroot_t *,
+                               struct buffer **,
+                               struct buffer **,
+                               int, int));
 #   ifndef CVS_AUTH_PORT
 #     define CVS_AUTH_PORT 2401
 #   endif /* CVS_AUTH_PORT */
+#   ifndef CVS_SAUTH_PORT
+#     define CVS_SAUTH_PORT 2402
+#   endif /* CVS_SAUTH_PORT */
 # endif /* AUTH_CLIENT_SUPPORT */
 
 # if HAVE_KERBEROS
Index: src/login.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/login.c,v
retrieving revision 1.66
diff -u -r1.66 login.c
--- src/login.c 16 May 2001 17:44:01 -0000      1.66
+++ src/login.c 21 May 2001 14:12:38 -0000
@@ -307,9 +307,10 @@
     char *p;
     int save_errno = 0;
 
-    if (root->method != pserver_method)
+    if (root->method != pserver_method && root->method != sserver_method)
     {
-       error (0, 0, "internal error: can only call password_entry_operation 
with pserver method");
+       error (0, 0, "internal error: can only call password_entry_operation 
with pserver and");
+       error (0, 0, "sserver methods");
        error (1, 0, "CVSROOT: %s", root->original);
     }
 
@@ -534,9 +535,10 @@
     if (argc < 0)
        usage (login_usage);
 
-    if (current_parsed_root->method != pserver_method)
+    if (current_parsed_root->method != pserver_method &&
+        current_parsed_root->method != sserver_method)
     {
-       error (0, 0, "can only use `login' command with the 'pserver' method");
+       error (0, 0, "can only use `login' command with the 'pserver' and 
'sserver' methods");
        error (1, 0, "CVSROOT: %s", current_parsed_root->original);
     }
 
@@ -562,7 +564,15 @@
      * will get zeroed by connect_to_server().  */
     cvs_password = xstrdup (typed_password);
 
-    connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0);
+    switch (current_parsed_root->method)
+    {
+       case pserver_method:
+           connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0);
+           break;
+       case sserver_method:
+           connect_to_sserver (current_parsed_root, NULL, NULL, 1, 0);
+           break;
+    }
 
     password_entry_operation (password_entry_add, current_parsed_root, 
typed_password);
 
@@ -605,9 +615,10 @@
         error (0, 0, "CVS_PASSWORD is no longer supported; ignored");
     }
 
-    if (current_parsed_root->method != pserver_method)
+    if (current_parsed_root->method != pserver_method
+       && current_parsed_root->method != sserver_method)
     {
-       error (0, 0, "can only call get_cvs_password with pserver method");
+       error (0, 0, "can only call get_cvs_password with pserver and sserver 
methods");
        error (1, 0, "CVSROOT: %s", current_parsed_root->original);
     }
 
Index: src/root.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/root.c,v
retrieving revision 1.52
diff -u -r1.52 root.c
--- src/root.c  29 Jan 2001 21:20:43 -0000      1.52
+++ src/root.c  21 May 2001 14:12:38 -0000
@@ -400,6 +400,8 @@
            newroot->method = local_method;
        else if (strcmp (method, "pserver") == 0)
            newroot->method = pserver_method;
+       else if (strcmp (method, "sserver") == 0)
+           newroot->method = sserver_method;
        else if (strcmp (method, "kserver") == 0)
            newroot->method = kserver_method;
        else if (strcmp (method, "gserver") == 0)
@@ -449,7 +451,7 @@
        {
            error (0, 0, "CVSROOT (\"%s\")", root_in);
            error (0, 0, "requires a path spec");
-           error (0, 0, 
":(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path");
+           error (0, 0, 
":(g|k|p|s)server:[[user][:password]@]host[:[port]]/path");
            error (0, 0, "[:(ext|server):][[user]@]host[:]/path");
            free (cvsroot_save);
            goto error_exit;
@@ -637,6 +639,7 @@
        check_hostname = 1;
        break;
     case pserver_method:
+    case sserver_method:
        check_hostname = 1;
        break;
     }
@@ -644,7 +647,7 @@
     if (no_password && newroot->password)
     {
        error (0, 0, "CVSROOT password specification is only valid for");
-       error (0, 0, "pserver connection method.");
+       error (0, 0, "pserver and sserver connection methods.");
        goto error_exit;
     }
 
@@ -657,7 +660,7 @@
     if (no_port && newroot->port)
        {
            error (0, 0, "CVSROOT port specification is only valid for gserver, 
kserver,");
-           error (0, 0, "and pserver connection methods.");
+           error (0, 0, "pserver, and sserver connection methods.");
            goto error_exit;
        }
 
@@ -693,8 +696,8 @@
     const cvsroot_t *root;
 {
     char *cvsroot_canonical;
-    char *p, *hostname, *username;
-    char port_s[64];
+    char *p, *hostname, *username, *method;
+    char port_s[32];
 
     /* get the appropriate port string */
     sprintf (port_s, "%d", get_cvs_port_number (root));
@@ -715,11 +718,24 @@
 
     /* get the username string */
     username = root->username ? root->username : getcaller();
-    cvsroot_canonical = xmalloc ( strlen(username)
+    switch (root->method)
+    {
+       case pserver_method:
+           method = "pserver";
+           break;
+       case sserver_method:
+           method = "sserver";
+           break;
+       default:
+           error (0, 0, "internal error: normalize_cvsroot only valid for the 
pserver and");
+           error (1, 0, "sserver access methods");
+    }
+    cvsroot_canonical = xmalloc ( strlen(method)
+                               + strlen(username)
                                + strlen(hostname) + strlen(port_s)
-                               + strlen(root->directory) + 12);
-    sprintf (cvsroot_canonical, ":pserver:%s@%s:%s%s",
-           username, hostname, port_s, root->directory);
+                               + strlen(root->directory) + 5);
+    sprintf (cvsroot_canonical, ":%s:%s@%s:%s%s",
+           method, username, hostname, port_s, root->directory);
 
     free (hostname);
     return cvsroot_canonical;
Index: src/root.h
===================================================================
RCS file: /home2/cvsroot/ccvs/src/root.h,v
retrieving revision 1.1
diff -u -r1.1 root.h
--- src/root.h  4 May 2001 16:36:34 -0000       1.1
+++ src/root.h  21 May 2001 14:12:38 -0000
@@ -15,6 +15,7 @@
     local_method,
     server_method,
     pserver_method,
+    sserver_method,
     kserver_method,
     gserver_method,
     ext_method,
Index: src/sanity.sh
===================================================================
RCS file: /home2/cvsroot/ccvs/src/sanity.sh,v
retrieving revision 1.694
diff -u -r1.694 sanity.sh
--- src/sanity.sh       30 Apr 2001 19:07:09 -0000      1.694
+++ src/sanity.sh       21 May 2001 14:12:47 -0000
@@ -15606,7 +15606,7 @@
 "${testcvs} -d :ext:`hostname`:crerepos init" \
 "${PROG} [a-z]*: CVSROOT (\":ext:${hostname}:crerepos\")
 ${PROG} [a-z]*: requires a path spec
-${PROG} [a-z]*: 
:(gserver|kserver|pserver):\[\[user\]\[:password\]@\]host\[:\[port\]\]/path
+${PROG} [a-z]*: 
:(g|k|p|s)server:\[\[user\]\[:password\]@\]host\[:\[port\]\]/path
 ${PROG} [a-z]*: \[:(ext|server):\]\[\[user\]@\]host\[:\]/path
 ${PROG} \[[a-z]* aborted\]: Bad CVSROOT\."
            cd ..

reply via email to

[Prev in Thread] Current Thread [Next in Thread]